mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +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_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_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));
|
||||
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");
|
||||
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) {
|
||||
zend_ast_decl *decl = (zend_ast_decl *) ast;
|
||||
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_class_entry *ce = emalloc(sizeof(zend_class_entry));
|
||||
zend_op *opline;
|
||||
znode extends_node;
|
||||
znode declare_node, extends_node;
|
||||
|
||||
if (CG(active_class_entry)) {
|
||||
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 (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. "
|
||||
"Traits can only be composed from other traits with the 'use' keyword. Error",
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->result.var = get_temporary_variable(CG(active_op_array));
|
||||
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;
|
||||
LITERAL_STR(opline->op2, lcname);
|
||||
|
||||
|
@ -6676,9 +6709,43 @@ void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) {
|
|||
|
||||
CG(active_class_entry) = ce;
|
||||
|
||||
if (implements_ast) {
|
||||
zend_compile_implements(&declare_node, implements_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;
|
||||
}
|
||||
|
|
|
@ -226,6 +226,8 @@ typedef struct _zend_try_catch_element {
|
|||
/* function has arguments with type hinting */
|
||||
#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);
|
||||
|
||||
|
||||
|
|
|
@ -415,12 +415,12 @@ unticked_class_declaration_statement:
|
|||
{ $$.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,
|
||||
Z_STR($2.u.constant), $3.u.ast, $4.u.ast, $7.u.ast); AS($$); }
|
||||
/*| interface_entry T_STRING
|
||||
{ zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); }
|
||||
interface_extends_list
|
||||
'{'
|
||||
class_statement_list
|
||||
'}' { AS($6); zend_do_end_class_declaration(&$1, NULL TSRMLS_CC); }*/
|
||||
| interface_entry T_STRING interface_extends_list
|
||||
{ $$.u.op.ptr = CG(doc_comment); CG(doc_comment) = NULL; }
|
||||
'{' class_statement_list '}'
|
||||
{ $$.u.ast = zend_ast_create_decl(ZEND_AST_CLASS, $1.EA, $1.u.op.opline_num,
|
||||
CG(zend_lineno), LANG_SCNG(yy_text), $4.u.op.ptr,
|
||||
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; }
|
||||
;
|
||||
|
||||
interface_entry:
|
||||
T_INTERFACE { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_INTERFACE; }
|
||||
;
|
||||
|
||||
extends_from:
|
||||
/* empty */ { $$.u.ast = NULL; }
|
||||
| T_EXTENDS name { $$.u.ast = $2.u.ast; }
|
||||
;
|
||||
|
||||
interface_entry:
|
||||
T_INTERFACE { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_INTERFACE; }
|
||||
interface_extends_list:
|
||||
/* empty */ { $$.u.ast = NULL; }
|
||||
| T_EXTENDS name_list { $$.u.ast = $2.u.ast; }
|
||||
;
|
||||
|
||||
/*interface_extends_list:
|
||||
/* empty /
|
||||
| T_EXTENDS interface_list
|
||||
;*/
|
||||
|
||||
implements_list:
|
||||
/* empty */ { $$.u.ast = NULL; }
|
||||
| T_IMPLEMENTS name_list { $$.u.ast = $2.u.ast; }
|
||||
|
@ -936,13 +936,6 @@ class_name:
|
|||
| 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 { $$.u.ast = $1.u.ast; }
|
||||
| new_variable { $$.u.ast = $1.u.ast; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue