Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Multi-purpose patch:

 - The fields of zend_namespace were not completely initialized which
   led to a variety of problems.
 - The occurrence of class/interface/namespace definition is now
   captured.
 - Functions/classes/interfaces/namespaces can be preceded by doc
   comments which are stored for use by extensions.
  • Loading branch information...
commit 5657b8369119dab9c81deb036d7a43c83df332cb 1 parent 383808e
Andrei Zmievski authored
View
6 Zend/zend.h
@@ -335,6 +335,12 @@ struct _zend_class_entry {
zend_class_entry **interfaces;
zend_uint num_interfaces;
+ char *filename;
+ zend_uint line_start;
+ zend_uint line_end;
+ char *doc_comment;
+ zend_uint doc_comment_len;
+
/* old handlers */
#if 0
void (*handle_function_call)(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
View
69 Zend/zend_compile.c
@@ -977,7 +977,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
op_array.ns = CG(active_namespace);
op_array.prototype = NULL;
- op_array.line_start = CG(zend_lineno);
+ op_array.line_start = zend_get_compiled_lineno(TSRMLS_C);
if (is_method) {
char *short_class_name = CG(active_class_entry)->name;
@@ -1071,12 +1071,16 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
}
-void zend_do_end_function_declaration(znode *function_token TSRMLS_DC)
+void zend_do_end_function_declaration(znode *function_token, znode *doc_comment TSRMLS_DC)
{
zend_do_extended_info(TSRMLS_C);
zend_do_return(NULL, 0 TSRMLS_CC);
pass_two(CG(active_op_array) TSRMLS_CC);
- CG(active_op_array)->line_end = CG(zend_lineno);
+ CG(active_op_array)->line_end = zend_get_compiled_lineno(TSRMLS_C);
+ if (doc_comment && doc_comment->op_type != IS_UNUSED) {
+ CG(active_op_array)->doc_comment = doc_comment->u.constant.value.str.val;
+ CG(active_op_array)->doc_comment_len = doc_comment->u.constant.value.str.len;
+ }
CG(active_op_array) = function_token->u.op_array;
/* Pop the switch and foreach seperators */
@@ -2202,6 +2206,8 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
new_class_entry->num_interfaces = 0;
zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);
+ new_class_entry->filename = zend_get_compiled_filename(TSRMLS_C);
+ new_class_entry->line_start = zend_get_compiled_lineno(TSRMLS_C);
new_class_entry->ce_flags |= class_token->u.constant.value.lval;
if (parent_class_name->op_type != IS_UNUSED) {
@@ -2245,10 +2251,17 @@ static void do_verify_abstract_class(TSRMLS_D)
}
-void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRMLS_DC)
+void zend_do_end_class_declaration(znode *class_token, znode *parent_token, znode *doc_comment TSRMLS_DC)
{
do_inherit_parent_constructor(CG(active_class_entry));
+ CG(active_class_entry)->line_end = zend_get_compiled_lineno(TSRMLS_C);
+
+ if (doc_comment && doc_comment->op_type != IS_UNUSED) {
+ CG(active_class_entry)->doc_comment = doc_comment->u.constant.value.str.val;
+ CG(active_class_entry)->doc_comment_len = doc_comment->u.constant.value.str.len;
+ }
+
if (CG(active_class_entry)->num_interfaces > 0) {
CG(active_class_entry)->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*CG(active_class_entry)->num_interfaces);
}
@@ -3279,7 +3292,6 @@ int zendlex(znode *zendlval TSRMLS_DC)
retval = lex_scan(&zendlval->u.constant TSRMLS_CC);
switch (retval) {
case T_COMMENT:
- case T_DOC_COMMENT:
case T_OPEN_TAG:
case T_WHITESPACE:
retval = zendlex(zendlval TSRMLS_CC);
@@ -3318,12 +3330,30 @@ void zend_destroy_property_info(zend_property_info *property_info)
void zend_init_namespace(zend_namespace *ns TSRMLS_DC)
{
+ ns->refcount = 1;
+ ns->constants_updated = 0;
+ ns->ce_flags = 0;
+
+ ns->filename = NULL;
+ ns->doc_comment = NULL;
+ ns->doc_comment_len = 0;
+
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->parent = NULL;
+ ns->ns = NULL;
ns->constructor = NULL;
+ ns->destructor = NULL;
+ ns->clone = NULL;
+ ns->__get = NULL;
+ ns->__set = NULL;
+ ns->__call = NULL;
+ ns->create_object = NULL;
+
ns->type = ZEND_NAMESPACE;
}
@@ -3346,6 +3376,7 @@ void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC)
ns->name_length = ns_name->u.constant.value.str.len;
zend_hash_add(&CG(global_namespace).class_table, ns->name, ns->name_length+1, (void **)&ns, sizeof(zend_namespace *), NULL);
zend_init_namespace(ns TSRMLS_CC);
+ ns->line_start = zend_get_compiled_lineno(TSRMLS_C);
}
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
@@ -3367,11 +3398,34 @@ void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC)
CG(function_table) = &ns->function_table;
}
-void zend_do_end_namespace(znode *ns_token TSRMLS_DC)
+void zend_do_end_namespace(znode *ns_token, znode *doc_comment TSRMLS_DC)
{
zend_namespace *ns = ns_token->u.previously_active_namespace;
zend_op *opline;
+ /*
+ * If the filename field has not been initialized yet, it means that we are
+ * on the first definition of namespace and should capture the definition
+ * information.
+ */
+ if (CG(active_namespace)->filename == NULL) {
+ CG(active_namespace)->filename = zend_get_compiled_filename(TSRMLS_C);
+ CG(active_namespace)->line_end = zend_get_compiled_lineno(TSRMLS_C);
+ }
+
+ if (doc_comment && doc_comment->op_type != IS_UNUSED) {
+ /*
+ * Do not overwrite previously declared doc comment in case the namespace is
+ * split over several parts.
+ */
+ if (CG(active_namespace)->doc_comment == NULL) {
+ CG(active_namespace)->doc_comment = doc_comment->u.constant.value.str.val;
+ CG(active_namespace)->doc_comment_len = doc_comment->u.constant.value.str.len;
+ } else {
+ zval_dtor(&doc_comment->u.constant);
+ }
+ }
+
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_START_NAMESPACE;
@@ -3436,6 +3490,9 @@ void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers
ce->constants_updated = 0;
ce->ce_flags = 0;
+ ce->doc_comment = NULL;
+ ce->doc_comment_len = 0;
+
zend_hash_init_ex(&ce->default_properties, 0, NULL, ZVAL_PTR_DTOR, persistent_hashes, 0);
zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) zend_destroy_property_info, persistent_hashes, 0);
View
12 Zend/zend_compile.h
@@ -148,8 +148,10 @@ struct _zend_op_array {
zend_bool uses_this;
char *filename;
- int line_start;
- int line_end;
+ zend_uint line_start;
+ zend_uint line_end;
+ char *doc_comment;
+ zend_uint doc_comment_len;
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};
@@ -318,7 +320,7 @@ void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC);
int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier);
void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC);
-void zend_do_end_function_declaration(znode *function_token TSRMLS_DC);
+void zend_do_end_function_declaration(znode *function_token, znode *doc_comment TSRMLS_DC);
void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, zend_uchar pass_type TSRMLS_DC);
int zend_do_begin_function_call(znode *function_name TSRMLS_DC);
void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC);
@@ -360,7 +362,7 @@ void zend_do_case_after_statement(znode *result, znode *case_token TSRMLS_DC);
void zend_do_default_before_statement(znode *case_list, znode *default_token TSRMLS_DC);
void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znode *parent_class_name TSRMLS_DC);
-void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRMLS_DC);
+void zend_do_end_class_declaration(znode *class_token, znode *parent_token, znode *doc_comment TSRMLS_DC);
void zend_do_declare_property(znode *var_name, znode *value, zend_uint access_type TSRMLS_DC);
void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC);
@@ -449,7 +451,7 @@ 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_do_end_namespace(znode *ns_token, znode *doc_comment 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);
View
2  Zend/zend_globals.h
@@ -85,8 +85,6 @@ struct _zend_compiler_globals {
int comment_start_line;
char *heredoc;
int heredoc_len;
- char *doc_comment;
- int doc_comment_len;
zend_op_array *active_op_array;
View
27 Zend/zend_language_parser.y
@@ -179,6 +179,7 @@ inner_statement:
statement:
unticked_statement { zend_do_ticks(TSRMLS_C); }
+ | doc_comment { zend_do_free(&$1 TSRMLS_CC); } unticked_statement { zend_do_ticks(TSRMLS_C); }
;
unticked_statement:
@@ -284,17 +285,27 @@ is_reference:
unticked_function_declaration_statement:
- T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type, NULL TSRMLS_CC); }
- '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); }
+ optional_doc_comment T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 0, $4.op_type, NULL TSRMLS_CC); }
+ '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2, &$1 TSRMLS_CC); }
;
unticked_class_declaration_statement:
- class_entry_type T_STRING extends_from
- { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
+ optional_doc_comment class_entry_type T_STRING extends_from
+ { zend_do_begin_class_declaration(&$2, &$3, &$4 TSRMLS_CC); }
implements_list
'{'
class_statement_list
- '}' { zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
+ '}' { zend_do_end_class_declaration(&$2, &$4, &$1 TSRMLS_CC); }
+;
+
+optional_doc_comment:
+ /* empty */ { $$.op_type = IS_UNUSED; }
+ | doc_comment { $$ = $1; }
+;
+
+
+doc_comment:
+ T_DOC_COMMENT { $$ = $1; }
;
@@ -305,7 +316,7 @@ class_entry_type:
;
namespace_declaration_statement:
- T_NAMESPACE namespace_name '{' { zend_do_begin_namespace(&$1, &$2 TSRMLS_CC); } namespace_statement_list '}' { zend_do_end_namespace(&$1 TSRMLS_CC); }
+ optional_doc_comment T_NAMESPACE namespace_name '{' { zend_do_begin_namespace(&$2, &$3 TSRMLS_CC); } namespace_statement_list '}' { zend_do_end_namespace(&$2, &$1 TSRMLS_CC); }
;
namespace_statement_list:
@@ -503,7 +514,9 @@ class_statement:
variable_modifiers { CG(access_type) = $1.u.constant.value.lval; } class_variable_declaration ';'
| 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 TSRMLS_CC); } '('
- parameter_list ')' method_body { zend_do_abstract_method(&$5, &$1, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
+ parameter_list ')' method_body { zend_do_abstract_method(&$5, &$1, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$2, NULL TSRMLS_CC); }
+ | doc_comment method_modifiers T_FUNCTION { $3.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$3, &$6, 1, $5.op_type, &$2 TSRMLS_CC); } '('
+ parameter_list ')' method_body { zend_do_abstract_method(&$6, &$2, &$11 TSRMLS_CC); zend_do_end_function_declaration(&$3, &$1 TSRMLS_CC); }
;
View
16 Zend/zend_language_scanner.l
@@ -124,8 +124,6 @@ void startup_scanner(TSRMLS_D)
{
CG(heredoc) = NULL;
CG(heredoc_len)=0;
- CG(doc_comment) = NULL;
- CG(doc_comment_len) = 0;
SCNG(yy_start_stack_ptr) = 0;
SCNG(yy_start_stack_depth) = 0;
}
@@ -137,10 +135,6 @@ void shutdown_scanner(TSRMLS_D)
efree(CG(heredoc));
CG(heredoc_len)=0;
}
- if (CG(doc_comment)) {
- efree(CG(doc_comment));
- CG(doc_comment_len) = 0;
- }
}
END_EXTERN_C()
@@ -1176,7 +1170,7 @@ NAMESPACE_NAME ({LABEL}":")+{LABEL}
}
}
-<ST_IN_SCRIPTING>"/** "{NEWLINE} {
+<ST_IN_SCRIPTING>"/**"{NEWLINE} {
CG(comment_start_line) = CG(zend_lineno);
BEGIN(ST_DOC_COMMENT);
yymore();
@@ -1194,11 +1188,9 @@ NAMESPACE_NAME ({LABEL}":")+{LABEL}
}
<ST_DOC_COMMENT>"*/" {
- if (CG(doc_comment)) {
- efree(CG(doc_comment));
- }
- CG(doc_comment) = estrndup(yytext, yyleng);
- CG(doc_comment_len) = yyleng;
+ zendlval->value.str.val = (char *)estrndup(yytext, yyleng);
+ zendlval->value.str.len = yyleng;
+ zendlval->type = IS_STRING;
HANDLE_NEWLINES(yytext, yyleng);
BEGIN(ST_IN_SCRIPTING);
return T_DOC_COMMENT;
View
11 Zend/zend_opcode.c
@@ -74,6 +74,8 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
op_array->function_name = NULL;
op_array->filename = zend_get_compiled_filename(TSRMLS_C);
+ op_array->doc_comment = NULL;
+ op_array->doc_comment_len = 0;
op_array->arg_types = NULL;
@@ -157,6 +159,9 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce)
if (ce->num_interfaces > 0) {
efree(ce->interfaces);
}
+ if (ce->doc_comment) {
+ efree(ce->doc_comment);
+ }
efree(ce);
break;
case ZEND_INTERNAL_CLASS:
@@ -184,6 +189,9 @@ ZEND_API void destroy_zend_namespace(zend_namespace **pns)
zend_hash_destroy(&ns->constants_table);
zend_hash_destroy(ns->static_members);
FREE_HASHTABLE(ns->static_members);
+ if (ns->doc_comment) {
+ efree(ns->doc_comment);
+ }
efree(ns->name);
efree(ns);
}
@@ -229,6 +237,9 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
if (op_array->function_name) {
efree(op_array->function_name);
}
+ if (op_array->doc_comment) {
+ efree(op_array->doc_comment);
+ }
if (op_array->arg_types) {
efree(op_array->arg_types);
}
Please sign in to comment.
Something went wrong with that request. Please try again.