1. Nested classes are gone.
2. New syntax for namespaces:
namespace foo {
class X { ... }
function bar { ... }
var x = 1;
const ZZ = 2;
}
3. Namespaced symbol access: $x = new foo::X; - etc.
For now, namespaces are case insensitive, just like classes.
Also, there can be no global class and namespace with the same name
(to avoid ambiguities in :: resolution).
#include "zend_ini.h"
#ifdef ZTS
-# define GLOBAL_FUNCTION_TABLE &global_main_class.function_table
-# define GLOBAL_CLASS_TABLE &global_main_class.class_table
-# define GLOBAL_CONSTANTS_TABLE &global_main_class.constants_table
+# define GLOBAL_FUNCTION_TABLE &global_namespace.function_table
+# define GLOBAL_CLASS_TABLE &global_namespace.class_table
+# define GLOBAL_CONSTANTS_TABLE &global_namespace.constants_table
# define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table
#else
# define GLOBAL_FUNCTION_TABLE CG(function_table)
ZEND_API int executor_globals_id;
ZEND_API int alloc_globals_id;
zend_class_entry global_main_class;
+zend_namespace global_namespace;
HashTable *global_auto_globals_table;
#endif
compiler_globals->compiled_filename = NULL;
- compiler_globals->function_table = &compiler_globals->main_class.function_table;
+ compiler_globals->function_table = &compiler_globals->global_namespace.function_table;
zend_hash_init_ex(compiler_globals->function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);
zend_hash_copy(compiler_globals->function_table, GLOBAL_FUNCTION_TABLE, NULL, &tmp_func, sizeof(zend_function));
- compiler_globals->class_table = &compiler_globals->main_class.class_table;
+ compiler_globals->class_table = &compiler_globals->global_namespace.class_table;
zend_hash_init_ex(compiler_globals->class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0);
zend_hash_copy(compiler_globals->class_table, GLOBAL_CLASS_TABLE, (copy_ctor_func_t) zend_class_add_ref, &tmp_class, sizeof(zend_class_entry *));
zend_version_info_length = sizeof(ZEND_CORE_VERSION_INFO)-1;
#ifndef ZTS
- GLOBAL_FUNCTION_TABLE = &compiler_globals.main_class.function_table;
- GLOBAL_CLASS_TABLE = &compiler_globals.main_class.class_table;
+ GLOBAL_FUNCTION_TABLE = &compiler_globals.global_namespace.function_table;
+ GLOBAL_CLASS_TABLE = &compiler_globals.global_namespace.class_table;
+ compiler_globals.global_namespace.static_members = NULL;
#endif
GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable));
zend_hash_init_ex(GLOBAL_FUNCTION_TABLE, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);
zend_uchar is_ref;
};
+struct _zend_op_array;
+/* typedef struct _zend_namespace {
+ char *name;
+ zend_uint name_length;
+ HashTable function_table;
+ HashTable class_table;
+ HashTable constants_table;
+ HashTable *global_variables;
+ struct _zend_op_array *op_array;
+} zend_namespace;
+*/
typedef struct _zend_function_entry {
char *fname;
HashTable *static_members;
HashTable constants_table;
zend_function_entry *builtin_functions;
+ struct _zend_class_entry *namespace;
union _zend_function *constructor;
union _zend_function *destructor;
union _zend_function *__set;
union _zend_function *__call;
+
/* handlers */
zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
#endif
};
+typedef struct _zend_class_entry zend_namespace; /* namespace is the same as class */
typedef struct _zend_utility_functions {
void (*error_function)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);
zend_stack_init(&CG(object_stack));
zend_stack_init(&CG(declare_stack));
CG(active_class_entry) = NULL;
- CG(active_ce_parent_class_name).value.str.val = NULL;
+ CG(active_namespace) = &CG(global_namespace);
zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0);
zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0);
zend_stack_init(&CG(list_stack));
op_array.fn_flags = fn_flags;
op_array.scope = CG(active_class_entry);
+ op_array.namespace = CG(active_namespace);
if (is_method) {
char *short_class_name = CG(active_class_entry)->name;
}
-void do_fetch_class(znode *result, znode *class_entry, znode *class_name TSRMLS_DC)
+void do_fetch_class(znode *result, znode *namespace_name, znode *class_name TSRMLS_DC)
{
long fetch_class_op_number;
zend_op *opline;
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_FETCH_CLASS;
- if (class_entry) {
- opline->op1 = *class_entry;
+ if (namespace_name) {
+ zend_str_tolower(namespace_name->u.constant.value.str.val, namespace_name->u.constant.value.str.len);
+ opline->op1 = *namespace_name;
} else {
SET_UNUSED(opline->op1);
CG(catch_begin) = fetch_class_op_number;
zend_initialize_class_data(new_class_entry, 1);
zend_str_tolower(new_class_entry->name, new_class_entry->name_length);
+
if (zend_hash_update(class_table, new_class_entry->name, name_length+1, &new_class_entry, sizeof(zend_class_entry *), NULL) == FAILURE) {
zend_error(E_COMPILE_ERROR, "Can't create class. Fatal error, please report!");
}
new_ce->refcount++;
if (zend_hash_add(&ce->class_table, last, strlen(last)+1, &new_ce, sizeof(zend_class_entry *), NULL) == FAILURE) {
new_ce->refcount--;
- zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", last);
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare class '%s' - class or namespace with this name already exist.", last);
return FAILURE;
}
return SUCCESS;
zend_function *function;
if (opline->opcode != ZEND_DECLARE_FUNCTION) {
- zend_error(E_ERROR, "Internal compiler error. Please report!");
+ zend_error(E_COMPILE_ERROR, "Internal compiler error. Please report!");
}
zend_hash_find(function_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void *) &function);
zend_class_entry *ce, **pce;
if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) {
- zend_error(E_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val);
+ zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val);
return FAILURE;
} else {
ce = *pce;
ce->refcount++;
if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) {
ce->refcount--;
- zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
return FAILURE;
} else {
return SUCCESS;
found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce);
if (found_ce == FAILURE) {
- zend_error(E_ERROR, "Cannot redeclare class %s", (*pce)->name);
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", (*pce)->name);
return FAILURE;
} else {
ce = *pce;
/* Register the derived class */
if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE) {
- zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
ce->refcount--;
zend_hash_destroy(&ce->function_table);
zend_hash_destroy(&ce->default_properties);
int doing_inheritance = 0;
zend_class_entry *new_class_entry = emalloc(sizeof(zend_class_entry));
- class_token->u.previously_active_class_entry = CG(active_class_entry);
if (!(strcmp(class_name->u.constant.value.str.val, "main") && strcmp(class_name->u.constant.value.str.val, "self") &&
strcmp(class_name->u.constant.value.str.val, "parent"))) {
zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val);
opline->op2.op_type = IS_CONST;
opline->op2.u.constant.type = IS_STRING;
opline->op2.u.constant.refcount = 1;
-
+
if (doing_inheritance) {
opline->extended_value = parent_class_name->u.var;
opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
opline->op2.u.constant.value.str.val = estrndup(new_class_entry->name, new_class_entry->name_length);
opline->op2.u.constant.value.str.len = new_class_entry->name_length;
-
+
zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL);
CG(active_class_entry) = new_class_entry;
}
void zend_do_end_class_declaration(znode *class_token TSRMLS_DC)
{
do_inherit_parent_constructor(CG(active_class_entry));
- CG(active_class_entry) = class_token->u.previously_active_class_entry;
- if (CG(active_ce_parent_class_name).value.str.val) {
- efree(CG(active_ce_parent_class_name).value.str.val);
- CG(active_ce_parent_class_name).value.str.val = NULL;
- }
+ CG(active_class_entry) = NULL;
}
void mangle_property_name(char **dest, int *dest_length, char *src1, int src1_length, char *src2, int src2_length)
efree(property_info->name);
}
+void zend_init_namespace(zend_namespace *ns TSRMLS_DC)
+{
+ zend_hash_init(&ns->function_table, 10, NULL, ZEND_FUNCTION_DTOR, 0);
+ zend_hash_init(&ns->class_table, 10, NULL, ZEND_CLASS_DTOR, 0);
+ zend_hash_init(&ns->constants_table, 10, NULL, ZVAL_PTR_DTOR, 0);
+ ALLOC_HASHTABLE(ns->static_members);
+ zend_hash_init(ns->static_members, 0, NULL, ZVAL_PTR_DTOR, 0);
+ ns->constructor = NULL;
+ ns->type = ZEND_NAMESPACE;
+}
+
+void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC)
+{
+ zend_namespace *ns = emalloc(sizeof(zend_namespace));
+ zend_op *opline;
+
+ zend_str_tolower(ns_name->u.constant.value.str.val, ns_name->u.constant.value.str.len);
+ ns->name = ns_name->u.constant.value.str.val;
+ ns->name_length = ns_name->u.constant.value.str.len;
+
+ if(zend_hash_add(&CG(global_namespace).class_table, ns->name, ns->name_length+1, (void **)&ns, sizeof(zend_namespace *), NULL) != SUCCESS) {
+ efree(ns);
+ zend_error(E_COMPILE_ERROR, "Cannot redefine namespace '%s' - class or namespace with this name already defined", ns->name);
+ }
+
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+
+ opline->opcode = ZEND_DECLARE_NAMESPACE;
+ opline->op1.op_type = IS_CONST;
+ opline->op1.u.constant.type = IS_STRING;
+ opline->op1.u.constant.value.str.val = estrndup(ns->name, ns->name_length);
+ opline->op1.u.constant.value.str.len = ns->name_length;
+ opline->op1.u.constant.refcount = 1;
+ SET_UNUSED(opline->op2);
+
+ zend_init_namespace(ns TSRMLS_CC);
+
+ ns->constructor = emalloc(sizeof(zend_op_array));
+ init_op_array((zend_op_array *)ns->constructor, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
+ ns->constructor->op_array.namespace = CG(active_namespace);
+
+ ns_token->u.op_array = CG(active_op_array);
+
+ CG(active_op_array) = &ns->constructor->op_array;
+ CG(active_namespace) = ns;
+
+ /* new symbol tables */
+ CG(class_table) = &ns->class_table;
+ CG(function_table) = &ns->function_table;
+
+ fprintf(stderr, "Start namespace '%s'\n", ns->name);
+}
+
+void zend_do_end_namespace(znode *ns_token TSRMLS_DC)
+{
+ zend_namespace *ns = CG(active_op_array)->namespace;
+ int handle = CG(handle_op_arrays);
+
+
+ zend_do_return(NULL, 0 TSRMLS_CC);
+ CG(handle_op_arrays) = 0;
+ pass_two(CG(active_op_array) TSRMLS_CC);
+ CG(handle_op_arrays) = handle;
+
+ CG(active_op_array)->namespace = CG(active_namespace);
+
+ CG(active_namespace) = ns;
+ CG(active_op_array) = ns_token->u.op_array;
+ /* restore symbol tables */
+ CG(class_table) = &CG(active_namespace)->class_table;
+ CG(function_table) = &CG(active_namespace)->function_table;
+
+ fprintf(stderr, "End namespace\n");
+}
+
+void zend_do_declare_namespace_var(znode *var_name, znode *value TSRMLS_DC)
+{
+ zval *var;
+
+ ALLOC_ZVAL(var);
+
+ if (value) {
+ *var = value->u.constant;
+ } else {
+ INIT_PZVAL(var);
+ var->type = IS_NULL;
+ }
+
+ zend_hash_update(CG(active_namespace)->static_members, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &var, sizeof(zval *), NULL);
+
+ FREE_PNODE(var_name);
+}
+
+void zend_do_declare_namespace_constant(znode *var_name, znode *value TSRMLS_DC)
+{
+ zval *var;
+
+ ALLOC_ZVAL(var);
+
+ if (value) {
+ *var = value->u.constant;
+ } else {
+ INIT_PZVAL(var);
+ var->type = IS_NULL;
+ }
+
+ zend_hash_update(&CG(active_namespace)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &var, sizeof(zval *), NULL);
+
+ FREE_PNODE(var_name);
+}
void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers)
{
ce->__call = NULL;
ce->create_object = NULL;
}
+
+ ce->namespace = CG(active_namespace);
}
/*
zend_uint var;
zend_uint opline_num; /* Needs to be signed */
zend_op_array *op_array;
- zend_class_entry *previously_active_class_entry; /* Used at compile-time */
zend_op *jmp_addr;
struct {
zend_uint var; /* dummy */
char *function_name; /* MUST be the third element of this struct! */
zend_class_entry *scope; /* MUST be the fourth element of this struct! */
zend_uint fn_flags; /* MUST be the fifth element of this struct! */
+ zend_namespace *namespace;
zend_uint *refcount;
char *function_name; /* MUST be the third element of this struct! */
zend_class_entry *scope; /* MUST be the fourth element of this struct! */
zend_uint fn_flags; /* MUST be the fifth element of this struct! */
+ zend_namespace *namespace;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
} zend_internal_function;
char *function_name;
zend_class_entry *scope;
zend_uint fn_flags;
+ zend_namespace *namespace;
} common;
zend_op_array op_array;
int zend_do_begin_function_call(znode *function_name TSRMLS_DC);
void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC);
void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC);
-void do_fetch_class(znode *result, znode *class_entry, znode *class_name TSRMLS_DC);
+void do_fetch_class(znode *result, znode *namespace_name, znode *class_name TSRMLS_DC);
void do_fetch_class_name(znode *result, znode *class_entry, znode *class_name, zend_bool case_sensitive TSRMLS_DC);
void zend_do_begin_class_member_function_call(znode *class_name, znode *function_name TSRMLS_DC);
void zend_do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC);
ZEND_API void destroy_zend_class(zend_class_entry **pce);
void zend_class_add_ref(zend_class_entry **ce);
+void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC);
+void zend_do_end_namespace(znode *ns_token TSRMLS_DC);
+void zend_init_namespace(zend_namespace *ns TSRMLS_DC);
+void zend_do_declare_namespace_var(znode *name, znode *value TSRMLS_DC);
+void zend_do_declare_namespace_constant(znode *name, znode *value TSRMLS_DC);
+ZEND_API void destroy_zend_namespace(zend_namespace **pns);
void zend_duplicate_property_info(zend_property_info *property_info);
void zend_destroy_property_info(zend_property_info *property_info);
#define ZEND_FUNCTION_DTOR (void (*)(void *)) destroy_zend_function
#define ZEND_CLASS_DTOR (void (*)(void *)) destroy_zend_class
+#define ZEND_NAMESPACE_DTOR (void (*)(void *)) destroy_zend_namespace
zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC);
void init_op(zend_op *op TSRMLS_DC);
#define ZEND_RAISE_ABSTRACT_ERROR 142
+#define ZEND_DECLARE_NAMESPACE 143
+
/* end of block */
#define ZEND_FETCH_CLASS_SELF 1
#define ZEND_FETCH_CLASS_PARENT 2
#define ZEND_FETCH_CLASS_MAIN 3
+#define ZEND_FETCH_CLASS_GLOBAL 4
/* variable parsing type (compile-time) */
#define ZEND_INTERNAL_CLASS 1
#define ZEND_USER_CLASS 2
+#define ZEND_NAMESPACE 3
#define ZEND_EVAL (1<<0)
#define ZEND_INCLUDE (1<<1)
int zend_startup_constants(TSRMLS_D)
{
- EG(zend_constants) = &CG(main_class).constants_table;
+ EG(zend_constants) = &CG(global_namespace).constants_table;
if (zend_hash_init(EG(zend_constants), 20, NULL, ZEND_CONSTANT_DTOR, 1)==FAILURE) {
return FAILURE;
*/
EX(function_state).function_symbol_table = NULL;
#endif
-
+ if(EG(active_namespace) != op_array->namespace) {
+ zend_switch_namespace(op_array->namespace TSRMLS_CC);
+ }
+
while (1) {
#ifdef ZEND_WIN32
if (EG(timed_out)) {
zval tmp;
int retval;
- if (EX(opline)->op1.op_type == IS_UNUSED) {
+ if (EX(opline)->op2.op_type == IS_UNUSED) {
if (EX(opline)->extended_value == ZEND_FETCH_CLASS_SELF) {
if (!EG(scope)) {
zend_error(E_ERROR, "Cannot access self:: when no class scope is active");
EX_T(EX(opline)->result.u.var).EA.class_entry = EG(scope);
NEXT_OPCODE();
} else if (EX(opline)->extended_value == ZEND_FETCH_CLASS_MAIN) {
- EX_T(EX(opline)->result.u.var).EA.class_entry = EG(main_class_ptr);
+ EX_T(EX(opline)->result.u.var).EA.class_entry = EG(global_namespace_ptr);
NEXT_OPCODE();
} else if (EX(opline)->extended_value == ZEND_FETCH_CLASS_PARENT) {
if (!EG(scope)) {
}
EX_T(EX(opline)->result.u.var).EA.class_entry = EG(scope)->parent;
NEXT_OPCODE();
- }
+ }
}
is_const = (EX(opline)->op2.op_type == IS_CONST);
class_name_strlen = tmp.value.str.len;
}
- if (EX(opline)->op1.op_type == IS_UNUSED) {
+ if (EX(opline)->op1.op_type == IS_UNUSED && EX(opline)->extended_value != ZEND_FETCH_CLASS_GLOBAL) {
retval = zend_lookup_class(class_name_strval, class_name_strlen, &pce TSRMLS_CC);
+
+ if(retval == FAILURE) {
+ /* try namespace */
+ if(zend_hash_find(&EG(global_namespace_ptr)->class_table, class_name_strval, class_name_strlen+1, (void **)&pce) == SUCCESS && (*pce)->type == ZEND_NAMESPACE) {
+ retval = SUCCESS;
+ }
+ }
+
} else {
- retval = zend_hash_find(&EX_T(EX(opline)->op1.u.var).EA.class_entry->class_table, class_name_strval, class_name_strlen+1, (void **)&pce);
+ zend_namespace *ns;
+ /* Looking for namespace */
+ if(EX(opline)->extended_value == ZEND_FETCH_CLASS_GLOBAL) {
+ ns = EG(global_namespace_ptr);
+ } else {
+ if (zend_hash_find(&EG(global_namespace_ptr)->class_table, EX(opline)->op1.u.constant.value.str.val, EX(opline)->op1.u.constant.value.str.len+1, (void **)&pce) == FAILURE || (*pce)->type != ZEND_NAMESPACE) {
+ zend_error(E_ERROR, "Namespace '%s' not found", EX(opline)->op1.u.constant.value.str.val);
+ }
+ ns = *pce;
+ }
+ retval = zend_hash_find(&ns->class_table, class_name_strval, class_name_strlen+1, (void **)&pce);
}
if (retval == FAILURE) {
}
*/
if (zend_hash_find(EG(function_table), function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) {
- zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval);
+ /* try global space also */
+ if(zend_hash_find(&EG(global_namespace_ptr)->function_table, function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) {
+ zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval);
+ }
}
EX(calling_scope) = function->common.scope;
EX(object) = NULL;
zend_class_entry *current_scope;
zval *current_this;
int return_value_used = RETURN_VALUE_USED(EX(opline));
-
+ zend_namespace *active_namespace = EG(active_namespace);
+
zend_ptr_stack_n_push(&EG(argument_stack), 2, (void *) EX(opline)->extended_value, NULL);
EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;
}
zend_ptr_stack_n_pop(&EG(arg_types_stack), 3, &EX(calling_scope), &EX(object), &EX(fbc));
+ if(EG(active_namespace) != active_namespace) {
+ zend_switch_namespace(active_namespace TSRMLS_CC);
+ }
EX(function_state).function = (zend_function *) op_array;
EG(function_state_ptr) = &EX(function_state);
zend_ptr_stack_clear_multiple(TSRMLS_C);
int zend_fetch_constant_handler(ZEND_OPCODE_HANDLER_ARGS)
{
- zend_class_entry *ce;
+ zend_class_entry *ce = NULL;
zval **value;
if (EX(opline)->op1.op_type == IS_UNUSED) {
NEXT_OPCODE();
}
}
+ if(EG(active_namespace) != EG(global_namespace_ptr)) {
+ /* if we are not global, go find in local constant table */
+ if (zend_hash_find(&EG(active_namespace)->constants_table, EX(opline)->op2.u.constant.value.str.val, EX(opline)->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) {
+ zval_update_constant(value, (void *) 1 TSRMLS_CC);
+ EX_T(EX(opline)->result.u.var).tmp_var = **value;
+ zval_copy_ctor(&EX_T(EX(opline)->result.u.var).tmp_var);
+ NEXT_OPCODE();
+ }
+ }
+
if (!zend_get_constant(EX(opline)->op2.u.constant.value.str.val, EX(opline)->op2.u.constant.value.str.len, &EX_T(EX(opline)->result.u.var).tmp_var TSRMLS_CC)) {
zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
EX(opline)->op2.u.constant.value.str.val,
ce = EX_T(EX(opline)->op1.u.var).EA.class_entry;
- if (&ce->constants_table == &EG(main_class_ptr)->constants_table) {
+ if (&ce->constants_table == &EG(global_namespace_ptr)->constants_table) {
if (!zend_get_constant(EX(opline)->op2.u.constant.value.str.val, EX(opline)->op2.u.constant.value.str.len, &EX_T(EX(opline)->result.u.var).tmp_var TSRMLS_CC)) {
zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
EX(opline)->op2.u.constant.value.str.val,
}
if (zend_hash_add(&EG(included_files), opened_path, strlen(opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) {
+ CG(active_namespace) = EG(active_namespace);
new_op_array = zend_compile_file(&file_handle, (EX(opline)->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE) TSRMLS_CC);
zend_destroy_file_handle(&file_handle TSRMLS_CC);
opened_path = NULL; /* zend_destroy_file_handle() already frees it */
break;
case ZEND_INCLUDE:
case ZEND_REQUIRE:
+ CG(active_namespace) = EG(active_namespace);
new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC);
break;
case ZEND_EVAL: {
char *eval_desc = zend_make_compiled_string_description("eval()'d code" TSRMLS_CC);
+ CG(active_namespace) = EG(active_namespace);
new_op_array = compile_string(inc_filename, eval_desc TSRMLS_CC);
efree(eval_desc);
}
if (new_op_array) {
zval *saved_object;
zend_function *saved_function;
-
+ zend_namespace *active_namespace = EG(active_namespace);
EG(return_value_ptr_ptr) = EX_T(EX(opline)->result.u.var).var.ptr_ptr;
EG(active_op_array) = new_op_array;
zend_execute(new_op_array TSRMLS_CC);
+ if(EG(active_namespace) != active_namespace) {
+ zend_switch_namespace(active_namespace TSRMLS_CC);
+ }
EX(function_state).function = saved_function;
EX(object) = saved_object;
NEXT_OPCODE();
}
+int zend_declare_namespace_handler(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_op_array *new_op_array=NULL;
+ zval **original_return_value = EG(return_value_ptr_ptr);
+ zval *namespace_name = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
+ zend_namespace **pns;
+ zval *saved_object;
+ zend_function *saved_function;
+ zend_namespace *active_namespace = EG(active_namespace);
+
+ if (Z_TYPE_P(namespace_name) != IS_STRING) {
+ zend_error(E_ERROR, "Internal error: Invalid type in namespace definition - %d", Z_TYPE_P(namespace_name));
+ }
+
+ if(zend_hash_find(&EG(global_namespace_ptr)->class_table, Z_STRVAL_P(namespace_name), Z_STRLEN_P(namespace_name)+1, (void **)&pns) != SUCCESS || (*pns)->type != ZEND_NAMESPACE) {
+ zend_error(E_ERROR, "Internal error: Cannot locate namespace '%s'", Z_STRVAL_P(namespace_name));
+ }
+
+ new_op_array = (*pns)->constructor;
+
+ FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1));
+ EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;
+
+ EG(return_value_ptr_ptr) = EX_T(EX(opline)->result.u.var).var.ptr_ptr;
+ EG(active_op_array) = new_op_array;
+ EX_T(EX(opline)->result.u.var).var.ptr = NULL;
+
+ saved_object = EX(object);
+ saved_function = EX(function_state).function;
+
+ EX(function_state).function = (zend_function *) new_op_array;
+ EX(object) = NULL;
+
+ zend_execute(new_op_array TSRMLS_CC);
+
+ if(EG(active_namespace) != active_namespace) {
+ zend_switch_namespace(active_namespace TSRMLS_CC);
+ }
+ EX(function_state).function = saved_function;
+ EX(object) = saved_object;
+
+ if (EX_T(EX(opline)->result.u.var).var.ptr) {
+ zval_ptr_dtor(&EX_T(EX(opline)->result.u.var).var.ptr);
+ }
+
+ EG(opline_ptr) = &EX(opline);
+ EG(active_op_array) = op_array;
+ EG(function_state_ptr) = &EX(function_state);
+ EG(return_value_ptr_ptr) = original_return_value;
+ NEXT_OPCODE();
+}
void zend_init_opcodes_handlers()
{
zend_opcode_handlers[ZEND_DECLARE_FUNCTION] = zend_declare_function_handler;
zend_opcode_handlers[ZEND_RAISE_ABSTRACT_ERROR] = zend_raise_abstract_error_handler;
+ zend_opcode_handlers[ZEND_DECLARE_NAMESPACE] = zend_declare_namespace_handler;
}
/*
}
ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC);
ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC);
+void zend_switch_namespace(zend_namespace *ns TSRMLS_DC);
static inline int i_zend_is_true(zval *op)
{
EG(exception) = NULL;
EG(scope) = NULL;
+ EG(active_namespace) = &CG(global_namespace);
- EG(main_class_ptr) = &CG(main_class);
- CG(main_class).static_members = &EG(symbol_table);
+ EG(global_namespace_ptr) = &CG(global_namespace);
+ CG(global_namespace).static_members = &EG(symbol_table);
EG(current_execute_data) = NULL;
void shutdown_executor(TSRMLS_D)
{
+ /* return to global namespace here */
+ if(EG(active_namespace) != EG(global_namespace_ptr)) {
+ zend_switch_namespace(EG(global_namespace_ptr));
+ }
+
zend_try {
zend_ptr_stack_destroy(&EG(arg_types_stack));
zend_class_entry *current_scope;
zend_class_entry *calling_scope = NULL;
zval *current_this;
-
+ zend_namespace *current_namespace = EG(active_namespace);
zend_execute_data execute_data;
/* Initialize execute_data */
}
zend_ptr_stack_clear_multiple(TSRMLS_C);
EG(function_state_ptr) = original_function_state_ptr;
+ EG(active_namespace) = current_namespace;
if (EG(This)) {
zval_ptr_dtor(&EG(This));
zval *retval_ptr;
int retval;
- if (EG(scope)) {
- if (zend_hash_find(&EG(scope)->class_table, name, name_length+1, (void **) ce) == SUCCESS) {
- return SUCCESS;
- }
- }
if (zend_hash_find(EG(class_table), name, name_length+1, (void **) ce) == SUCCESS) {
return SUCCESS;
}
#endif
}
+void zend_switch_namespace(zend_namespace *ns TSRMLS_DC)
+{
+ if(NULL == ns) {
+ return;
+ }
+ EG(active_namespace) = ns;
+ EG(function_table) = &ns->function_table;
+ EG(class_table) = &ns->class_table;
+/* EG(zend_constants) = &ns->constants_table; */
+}
+
/*
* Local variables:
* tab-width: 4
zend_stack declare_stack;
zend_class_entry *active_class_entry;
- zval active_ce_parent_class_name;
+ zend_namespace *active_namespace;
/* variables for list() compilation */
zend_llist list_llist;
zend_op_array *active_op_array;
- zend_class_entry main_class;
+ zend_namespace global_namespace;
+
HashTable *function_table; /* function symbol table */
HashTable *class_table; /* class table */
+ HashTable namespace_table; /* namespaces */
HashTable filenames_table;
HashTable *zend_constants; /* constants table */
zend_class_entry *scope;
- zend_class_entry *main_class_ptr;
+ zend_namespace *global_namespace_ptr;
+ zend_namespace *active_namespace;
zval *This;
%token T_CURLY_OPEN
%token T_PAAMAYIM_NEKUDOTAYIM
%token T_IMPORT T_FROM
+%token T_NAMESPACE_NAME
+%token T_NAMESPACE
%% /* Rules */
statement
| function_declaration_statement { zend_do_early_binding(TSRMLS_C); }
| class_declaration_statement
+ | namespace_declaration_statement
;
| T_DECLARE { $1.u.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); }
| ';' /* empty statement */
| T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}'
- T_CATCH '(' catch_or_import_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8, &$9, 1 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
+ T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8, &$9, 1 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
additional_catches
| T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); }
- | T_IMPORT { zend_do_begin_import(TSRMLS_C); } import_rule T_FROM catch_or_import_class_entry { zend_do_end_import(&$5 TSRMLS_CC); } ';'
+ | T_IMPORT { zend_do_begin_import(TSRMLS_C); } import_rule T_FROM import_namespace { zend_do_end_import(&$5 TSRMLS_CC); } ';'
;
;
non_empty_additional_catches:
- non_empty_additional_catches T_CATCH '(' catch_or_import_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); }
- | T_CATCH '(' catch_or_import_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$4, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
+ non_empty_additional_catches T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); }
+ | T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$4, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
;
T_CLASS declaration_class_name extends_from '{' { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } class_statement_list '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); }
;
+namespace_declaration_statement:
+ T_NAMESPACE T_STRING '{' { zend_do_begin_namespace(&$1, &$2 TSRMLS_CC); } namespace_statement_list '}' { zend_do_end_namespace(&$1 TSRMLS_CC); }
+;
+
+namespace_statement_list:
+ namespace_statement_list namespace_statement
+ | /* empty */
+;
+
+namespace_statement:
+ T_VAR namespace_var_declaration_list ';'
+ | namespace_const_declaration ';'
+ | function_declaration_statement { zend_do_early_binding(TSRMLS_C); }
+ | class_declaration_statement
+ | namespace_declaration_statement
+;
+
+namespace_var_declaration_list:
+ namespace_var_declaration_list ',' namespace_var_declaration
+ | namespace_var_declaration
+;
+
+namespace_var_declaration:
+ T_VARIABLE { zend_do_declare_namespace_var(&$1, NULL TSRMLS_CC); }
+ | T_VARIABLE '=' static_scalar { zend_do_declare_namespace_var(&$1, &$3 TSRMLS_CC); }
+;
+
+namespace_const_declaration:
+ namespace_const_declaration ',' T_STRING '=' static_scalar { zend_do_declare_namespace_constant(&$3, &$5 TSRMLS_CC); }
+ | T_CONST T_STRING '=' static_scalar { zend_do_declare_namespace_constant(&$2, &$4 TSRMLS_CC); }
+;
+
extends_from:
- /* empty */ { $$.op_type = IS_UNUSED; }
- | T_EXTENDS catch_or_import_class_entry { $$ = $2; }
+ /* empty */ { $$.op_type = IS_UNUSED; }
+ | T_EXTENDS catch_class_entry { $$ = $2; }
;
declaration_class_name:
- | parse_class_name_entry T_STRING { do_fetch_class_name(&$$, &$1, &$2, 0 TSRMLS_CC); }
+ | namespace_prefix T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class_name(&$$, &$1, &$3, 0 TSRMLS_CC); }
| T_STRING { $$ = $1; zend_str_tolower($$.u.constant.value.str.val, $$.u.constant.value.str.len); }
;
global_var:
T_VARIABLE { $$ = $1; }
- | '$' r_variable { $$ = $2; }
+ | '$' r_variable { $$ = $2; }
| '$' '{' expr '}' { $$ = $3; }
;
| class_constant_declaration ';'
| method_modifiers T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, $1.u.constant.value.lval TSRMLS_CC); } '('
parameter_list ')' method_body { zend_do_abstract_method(&$5, &$1, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
- | T_CLASS T_STRING extends_from '{' { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } class_statement_list '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); }
;
;
parse_class_entry:
- parse_class_entry T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class(&$$, &$1, &$2 TSRMLS_CC); }
+ T_NAMESPACE_NAME T_PAAMAYIM_NEKUDOTAYIM T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); }
| T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); }
;
-parse_class_name_entry:
- parse_class_name_entry T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class_name(&$$, &$1, &$2, 0 TSRMLS_CC); }
- | T_STRING T_PAAMAYIM_NEKUDOTAYIM { $$ = $1; zend_str_tolower($$.u.constant.value.str.val, $$.u.constant.value.str.len); }
-;
+catch_class_entry:
+ namespace_prefix T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); }
+ | T_STRING { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); }
+ ;
-catch_or_import_class_entry:
- parse_class_entry T_STRING { do_fetch_class(&$$, &$1, &$2 TSRMLS_CC); }
+import_namespace:
+ T_NAMESPACE_NAME { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); }
| T_STRING { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); }
;
new_class_entry:
- parse_class_entry static_or_variable_string { do_fetch_class(&$$, &$1, &$2 TSRMLS_CC); }
+ namespace_prefix T_PAAMAYIM_NEKUDOTAYIM static_or_variable_string { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); }
| static_or_variable_string { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); }
;
+namespace_prefix:
+ T_NAMESPACE_NAME { $$ = $1; }
+ | T_STRING { $$ = $1; }
+;
+
static_or_variable_string:
T_STRING { $$ = $1; }
| r_variable_without_static_member { $$ = $1; }
;
instanceof_expr:
- parse_class_entry T_STRING { do_fetch_class(&$$, &$1, &$2 TSRMLS_CC); }
+ namespace_prefix T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); }
| T_STRING { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); }
;
| '+' static_scalar { $$ = $2; }
| '-' static_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; }
| T_ARRAY '(' static_array_pair_list ')' { $$ = $3; $$.u.constant.type = IS_CONSTANT_ARRAY; }
- | parse_class_name_entry T_STRING { zend_do_fetch_constant(&$$, &$1, &$2, ZEND_CT TSRMLS_CC); }
+ | namespace_prefix T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_CT TSRMLS_CC); }
;
init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
CG(in_compilation) = 1;
CG(active_op_array) = op_array;
+ op_array->namespace = CG(active_namespace);
compiler_result = zendparse(TSRMLS_C);
zend_do_return(&retval_znode, 0 TSRMLS_CC);
CG(in_compilation) = original_in_compilation;
} else {
init_op_array(op_array, ZEND_EVAL_CODE, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
CG(active_op_array) = op_array;
+ op_array->namespace = CG(active_namespace);
BEGIN(ST_IN_SCRIPTING);
compiler_result = zendparse(TSRMLS_C);
ESCAPED_AND_WHITESPACE [\n\t\r #'.:;,()|^&+-/*=%!~<>?@]+
ANY_CHAR (.|[\n])
NEWLINE ("\r"|"\n"|"\r\n")
+NAMESPACE_NAME ({LABEL}":")+{LABEL}
%option noyylineno
%option noyywrap
return T_EXTENDS;
}
+<ST_IN_SCRIPTING>"namespace" {
+ return T_NAMESPACE;
+}
+
<ST_IN_SCRIPTING,ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"->" {
yy_push_state(ST_LOOKING_FOR_PROPERTY TSRMLS_CC);
return T_OBJECT_OPERATOR;
return T_STRING;
}
+<ST_IN_SCRIPTING>{NAMESPACE_NAME} {
+ int i;
+
+ zendlval->value.str.val = (char *)estrndup(yytext, yyleng);
+ zendlval->value.str.len = yyleng;
+ zendlval->type = IS_STRING;
+
+ /* Nuke this code */
+ for (i=0; i<yyleng; i++) {
+ if (zendlval->value.str.val[i] == ':') {
+ zendlval->value.str.val[i] = '_';
+ }
+ }
+ return T_NAMESPACE_NAME;
+}
<ST_HEREDOC>{ENCAPSED_STRING} {
zendlval->value.str.val = (char *)estrndup(yytext, yyleng);
op_array->arg_types = NULL;
op_array->scope = NULL;
+ op_array->namespace = NULL;
op_array->brk_cont_array = NULL;
op_array->last_brk_cont = 0;
zend_hash_destroy(&ce->class_table);
free(ce);
break;
+ case ZEND_NAMESPACE:
+ destroy_zend_namespace(pce);
+ break;
}
}
+ZEND_API void destroy_zend_namespace(zend_namespace **pns)
+{
+ zend_namespace *ns = *pns;
+ zend_hash_destroy(&ns->function_table);
+ zend_hash_destroy(&ns->class_table);
+ zend_hash_destroy(&ns->constants_table);
+ zend_hash_destroy(ns->static_members);
+ FREE_HASHTABLE(ns->static_members);
+ destroy_op_array(ns->constructor);
+ efree(ns->constructor);
+ efree(ns->name);
+ efree(ns);
+}
void zend_class_add_ref(zend_class_entry **ce)
{