mirror of
https://github.com/php/php-src.git
synced 2025-08-16 22:18:50 +02:00
Mostly finish class declarations (~50 failing tests)
This commit is contained in:
parent
b24bda6be1
commit
005315510a
3 changed files with 88 additions and 26 deletions
|
@ -6045,7 +6045,7 @@ void zend_begin_method_decl(
|
||||||
) {
|
) {
|
||||||
zend_class_entry *ce = CG(active_class_entry);
|
zend_class_entry *ce = CG(active_class_entry);
|
||||||
zend_bool in_interface = (ce->ce_flags & ZEND_ACC_INTERFACE) != 0;
|
zend_bool in_interface = (ce->ce_flags & ZEND_ACC_INTERFACE) != 0;
|
||||||
zend_bool in_trait = (ce->ce_flags & ZEND_ACC_TRAIT) != 0;
|
zend_bool in_trait = ZEND_CE_IS_TRAIT(ce);
|
||||||
zend_bool is_public = (op_array->fn_flags & ZEND_ACC_PUBLIC) != 0;
|
zend_bool is_public = (op_array->fn_flags & ZEND_ACC_PUBLIC) != 0;
|
||||||
zend_bool is_static = (op_array->fn_flags & ZEND_ACC_STATIC) != 0;
|
zend_bool is_static = (op_array->fn_flags & ZEND_ACC_STATIC) != 0;
|
||||||
|
|
||||||
|
@ -6424,7 +6424,7 @@ void zend_compile_class_const_decl(zend_ast *ast TSRMLS_DC) {
|
||||||
zend_string *name = Z_STR_P(zend_ast_get_zval(name_ast));
|
zend_string *name = Z_STR_P(zend_ast_get_zval(name_ast));
|
||||||
zval value_zv;
|
zval value_zv;
|
||||||
|
|
||||||
if (ce->ce_flags & ZEND_ACC_TRAIT) {
|
if (ZEND_CE_IS_TRAIT(ce)) {
|
||||||
zend_error_noreturn(E_COMPILE_ERROR, "Traits cannot have constants");
|
zend_error_noreturn(E_COMPILE_ERROR, "Traits cannot have constants");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6574,6 +6574,35 @@ void zend_compile_use_trait(zend_ast *ast TSRMLS_DC) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void zend_compile_implements(znode *class_node, zend_ast *ast TSRMLS_DC) {
|
||||||
|
zend_uint i;
|
||||||
|
for (i = 0; i < ast->children; ++i) {
|
||||||
|
zend_ast *class_ast = ast->child[i];
|
||||||
|
zend_string *name = Z_STR_P(zend_ast_get_zval(class_ast));
|
||||||
|
|
||||||
|
zend_op *opline;
|
||||||
|
|
||||||
|
/* Traits can not implement interfaces */
|
||||||
|
if (ZEND_CE_IS_TRAIT(CG(active_class_entry))) {
|
||||||
|
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as interface on '%s' "
|
||||||
|
"since it is a Trait", name->val, CG(active_class_entry)->name->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!zend_is_const_default_class_ref(class_ast)) {
|
||||||
|
zend_error_noreturn(E_COMPILE_ERROR,
|
||||||
|
"Cannot use '%s' as interface name as it is reserved", name->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
opline = emit_op(NULL, ZEND_ADD_INTERFACE, class_node, NULL TSRMLS_CC);
|
||||||
|
opline->extended_value = ZEND_FETCH_CLASS_INTERFACE;
|
||||||
|
opline->op2_type = IS_CONST;
|
||||||
|
opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
|
||||||
|
zend_resolve_class_name_ast(class_ast TSRMLS_CC) TSRMLS_CC);
|
||||||
|
|
||||||
|
CG(active_class_entry)->num_interfaces++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) {
|
void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) {
|
||||||
zend_ast_decl *decl = (zend_ast_decl *) ast;
|
zend_ast_decl *decl = (zend_ast_decl *) ast;
|
||||||
zend_ast *extends_ast = decl->child[0];
|
zend_ast *extends_ast = decl->child[0];
|
||||||
|
@ -6583,7 +6612,7 @@ void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) {
|
||||||
zend_string *name = decl->name, *lcname, *import_name = NULL;
|
zend_string *name = decl->name, *lcname, *import_name = NULL;
|
||||||
zend_class_entry *ce = emalloc(sizeof(zend_class_entry));
|
zend_class_entry *ce = emalloc(sizeof(zend_class_entry));
|
||||||
zend_op *opline;
|
zend_op *opline;
|
||||||
znode extends_node;
|
znode declare_node, extends_node;
|
||||||
|
|
||||||
if (CG(active_class_entry)) {
|
if (CG(active_class_entry)) {
|
||||||
zend_error_noreturn(E_COMPILE_ERROR, "Class declarations may not be nested");
|
zend_error_noreturn(E_COMPILE_ERROR, "Class declarations may not be nested");
|
||||||
|
@ -6637,7 +6666,7 @@ void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extends_ast) {
|
if (extends_ast) {
|
||||||
if (ce->ce_flags & ZEND_ACC_TRAIT) {
|
if (ZEND_CE_IS_TRAIT(ce)) {
|
||||||
zend_error_noreturn(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. "
|
zend_error_noreturn(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. "
|
||||||
"Traits can only be composed from other traits with the 'use' keyword. Error",
|
"Traits can only be composed from other traits with the 'use' keyword. Error",
|
||||||
name->val);
|
name->val);
|
||||||
|
@ -6651,10 +6680,14 @@ void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) {
|
||||||
zend_compile_class_ref(&extends_node, extends_ast TSRMLS_CC);
|
zend_compile_class_ref(&extends_node, extends_ast TSRMLS_CC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||||
opline->result.var = get_temporary_variable(CG(active_op_array));
|
opline->result.var = get_temporary_variable(CG(active_op_array));
|
||||||
opline->result_type = IS_VAR;
|
opline->result_type = IS_VAR;
|
||||||
|
GET_NODE(&declare_node, opline->result);
|
||||||
|
|
||||||
|
// TODO.AST drop this
|
||||||
|
GET_NODE(&CG(implementing_class), opline->result);
|
||||||
|
|
||||||
opline->op2_type = IS_CONST;
|
opline->op2_type = IS_CONST;
|
||||||
LITERAL_STR(opline->op2, lcname);
|
LITERAL_STR(opline->op2, lcname);
|
||||||
|
|
||||||
|
@ -6676,9 +6709,43 @@ void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) {
|
||||||
|
|
||||||
CG(active_class_entry) = ce;
|
CG(active_class_entry) = ce;
|
||||||
|
|
||||||
|
if (implements_ast) {
|
||||||
|
zend_compile_implements(&declare_node, implements_ast TSRMLS_CC);
|
||||||
|
}
|
||||||
|
|
||||||
zend_compile_stmt(stmt_ast TSRMLS_CC);
|
zend_compile_stmt(stmt_ast TSRMLS_CC);
|
||||||
|
|
||||||
// TODO.AST traits, interfaces, extends, etc
|
// TODO.AST validity checks
|
||||||
|
|
||||||
|
/* Check for traits and proceed like with interfaces.
|
||||||
|
* The only difference will be a combined handling of them in the end.
|
||||||
|
* Thus, we need another opcode here. */
|
||||||
|
if (ce->num_traits > 0) {
|
||||||
|
ce->traits = NULL;
|
||||||
|
ce->num_traits = 0;
|
||||||
|
ce->ce_flags |= ZEND_ACC_IMPLEMENT_TRAITS;
|
||||||
|
|
||||||
|
emit_op(NULL, ZEND_BIND_TRAITS, &declare_node, NULL TSRMLS_CC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
|
||||||
|
&& (extends_ast || ce->num_interfaces > 0)
|
||||||
|
) {
|
||||||
|
zend_verify_abstract_class(ce TSRMLS_CC);
|
||||||
|
if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) {
|
||||||
|
do_verify_abstract_class(TSRMLS_C);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inherit interfaces; reset number to zero, we need it for above check and
|
||||||
|
* will restore it during actual implementation.
|
||||||
|
* The ZEND_ACC_IMPLEMENT_INTERFACES flag disables double call to
|
||||||
|
* zend_verify_abstract_class() */
|
||||||
|
if (ce->num_interfaces > 0) {
|
||||||
|
ce->interfaces = NULL;
|
||||||
|
ce->num_interfaces = 0;
|
||||||
|
ce->ce_flags |= ZEND_ACC_IMPLEMENT_INTERFACES;
|
||||||
|
}
|
||||||
|
|
||||||
CG(active_class_entry) = NULL;
|
CG(active_class_entry) = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,6 +226,8 @@ typedef struct _zend_try_catch_element {
|
||||||
/* function has arguments with type hinting */
|
/* function has arguments with type hinting */
|
||||||
#define ZEND_ACC_HAS_TYPE_HINTS 0x10000000
|
#define ZEND_ACC_HAS_TYPE_HINTS 0x10000000
|
||||||
|
|
||||||
|
#define ZEND_CE_IS_TRAIT(ce) (((ce)->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT)
|
||||||
|
|
||||||
char *zend_visibility_string(zend_uint fn_flags);
|
char *zend_visibility_string(zend_uint fn_flags);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -415,12 +415,12 @@ unticked_class_declaration_statement:
|
||||||
{ $$.u.ast = zend_ast_create_decl(ZEND_AST_CLASS, $1.EA, $1.u.op.opline_num,
|
{ $$.u.ast = zend_ast_create_decl(ZEND_AST_CLASS, $1.EA, $1.u.op.opline_num,
|
||||||
CG(zend_lineno), LANG_SCNG(yy_text), $5.u.op.ptr,
|
CG(zend_lineno), LANG_SCNG(yy_text), $5.u.op.ptr,
|
||||||
Z_STR($2.u.constant), $3.u.ast, $4.u.ast, $7.u.ast); AS($$); }
|
Z_STR($2.u.constant), $3.u.ast, $4.u.ast, $7.u.ast); AS($$); }
|
||||||
/*| interface_entry T_STRING
|
| interface_entry T_STRING interface_extends_list
|
||||||
{ zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); }
|
{ $$.u.op.ptr = CG(doc_comment); CG(doc_comment) = NULL; }
|
||||||
interface_extends_list
|
'{' class_statement_list '}'
|
||||||
'{'
|
{ $$.u.ast = zend_ast_create_decl(ZEND_AST_CLASS, $1.EA, $1.u.op.opline_num,
|
||||||
class_statement_list
|
CG(zend_lineno), LANG_SCNG(yy_text), $4.u.op.ptr,
|
||||||
'}' { AS($6); zend_do_end_class_declaration(&$1, NULL TSRMLS_CC); }*/
|
Z_STR($2.u.constant), NULL, $3.u.ast, $6.u.ast); AS($$); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -431,20 +431,20 @@ class_entry_type:
|
||||||
| T_FINAL T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_FINAL_CLASS; }
|
| T_FINAL T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_FINAL_CLASS; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
interface_entry:
|
||||||
|
T_INTERFACE { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_INTERFACE; }
|
||||||
|
;
|
||||||
|
|
||||||
extends_from:
|
extends_from:
|
||||||
/* empty */ { $$.u.ast = NULL; }
|
/* empty */ { $$.u.ast = NULL; }
|
||||||
| T_EXTENDS name { $$.u.ast = $2.u.ast; }
|
| T_EXTENDS name { $$.u.ast = $2.u.ast; }
|
||||||
;
|
;
|
||||||
|
|
||||||
interface_entry:
|
interface_extends_list:
|
||||||
T_INTERFACE { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_INTERFACE; }
|
/* empty */ { $$.u.ast = NULL; }
|
||||||
|
| T_EXTENDS name_list { $$.u.ast = $2.u.ast; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/*interface_extends_list:
|
|
||||||
/* empty /
|
|
||||||
| T_EXTENDS interface_list
|
|
||||||
;*/
|
|
||||||
|
|
||||||
implements_list:
|
implements_list:
|
||||||
/* empty */ { $$.u.ast = NULL; }
|
/* empty */ { $$.u.ast = NULL; }
|
||||||
| T_IMPLEMENTS name_list { $$.u.ast = $2.u.ast; }
|
| T_IMPLEMENTS name_list { $$.u.ast = $2.u.ast; }
|
||||||
|
@ -936,13 +936,6 @@ class_name:
|
||||||
| name { $$.u.ast = $1.u.ast; }
|
| name { $$.u.ast = $1.u.ast; }
|
||||||
;
|
;
|
||||||
|
|
||||||
fully_qualified_class_name:
|
|
||||||
namespace_name { $$ = $1; }
|
|
||||||
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); }
|
|
||||||
| T_NS_SEPARATOR namespace_name { zval tmp; ZVAL_NEW_STR(&tmp, STR_ALLOC(Z_STRLEN($2.u.constant)+1, 0)); Z_STRVAL(tmp)[0] = '\\'; memcpy(Z_STRVAL(tmp) + 1, Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); if (Z_DELREF($2.u.constant) == 0) {efree(Z_STR($2.u.constant));} Z_STR($2.u.constant) = Z_STR(tmp); $$ = $2; }
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
class_name_reference:
|
class_name_reference:
|
||||||
class_name { $$.u.ast = $1.u.ast; }
|
class_name { $$.u.ast = $1.u.ast; }
|
||||||
| new_variable { $$.u.ast = $1.u.ast; }
|
| new_variable { $$.u.ast = $1.u.ast; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue