mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Partial port of class declarations
This commit is contained in:
parent
461bce5222
commit
b24bda6be1
@ -350,6 +350,7 @@ ZEND_API void zend_ast_destroy(zend_ast *ast)
|
||||
case ZEND_AST_FUNC_DECL:
|
||||
case ZEND_AST_CLOSURE:
|
||||
case ZEND_AST_METHOD:
|
||||
case ZEND_AST_CLASS:
|
||||
{
|
||||
zend_ast_decl *decl = (zend_ast_decl *) ast;
|
||||
STR_RELEASE(decl->name);
|
||||
|
@ -116,6 +116,8 @@ enum _zend_ast_kind {
|
||||
ZEND_AST_TRAIT_PRECEDENCE,
|
||||
ZEND_AST_TRAIT_ALIAS,
|
||||
ZEND_AST_METHOD_REFERENCE,
|
||||
|
||||
ZEND_AST_CLASS,
|
||||
};
|
||||
|
||||
typedef unsigned short zend_ast_kind;
|
||||
|
@ -6574,6 +6574,115 @@ void zend_compile_use_trait(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 *extends_ast = decl->child[0];
|
||||
zend_ast *implements_ast = decl->child[1];
|
||||
zend_ast *stmt_ast = decl->child[2];
|
||||
|
||||
zend_string *name = decl->name, *lcname, *import_name = NULL;
|
||||
zend_class_entry *ce = emalloc(sizeof(zend_class_entry));
|
||||
zend_op *opline;
|
||||
znode extends_node;
|
||||
|
||||
if (CG(active_class_entry)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Class declarations may not be nested");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name->val, name->len)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved",
|
||||
name->val);
|
||||
}
|
||||
|
||||
lcname = STR_ALLOC(name->len, 0);
|
||||
zend_str_tolower_copy(lcname->val, name->val, name->len);
|
||||
|
||||
if (CG(current_import)) {
|
||||
import_name = zend_hash_find_ptr(CG(current_import), lcname);
|
||||
}
|
||||
|
||||
if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) {
|
||||
name = zend_concat_names(Z_STRVAL(CG(current_namespace)), Z_STRLEN(CG(current_namespace)),
|
||||
name->val, name->len);
|
||||
|
||||
STR_RELEASE(lcname);
|
||||
lcname = STR_ALLOC(name->len, 0);
|
||||
zend_str_tolower_copy(lcname->val, name->val, name->len);
|
||||
} else {
|
||||
STR_ADDREF(name);
|
||||
}
|
||||
|
||||
if (import_name) {
|
||||
char *import_name_lc = zend_str_tolower_dup(import_name->val, import_name->len);
|
||||
if (lcname->len != import_name->len
|
||||
|| memcmp(import_name_lc, lcname->val, lcname->len)
|
||||
) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare class %s "
|
||||
"because the name is already in use", name->val);
|
||||
}
|
||||
efree(import_name_lc);
|
||||
}
|
||||
|
||||
ce->type = ZEND_USER_CLASS;
|
||||
ce->name = zend_new_interned_string(name TSRMLS_CC);
|
||||
zend_initialize_class_data(ce, 1 TSRMLS_CC);
|
||||
|
||||
ce->ce_flags |= decl->flags;
|
||||
ce->info.user.filename = zend_get_compiled_filename(TSRMLS_C);
|
||||
ce->info.user.line_start = decl->start_lineno;
|
||||
ce->info.user.line_end = decl->end_lineno;
|
||||
if (decl->doc_comment) {
|
||||
ce->info.user.doc_comment = STR_COPY(decl->doc_comment);
|
||||
}
|
||||
|
||||
if (extends_ast) {
|
||||
if (ce->ce_flags & ZEND_ACC_TRAIT) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (!zend_is_const_default_class_ref(extends_ast)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"Cannot use '%s' as class name as it is reserved", name->val);
|
||||
}
|
||||
|
||||
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;
|
||||
opline->op2_type = IS_CONST;
|
||||
LITERAL_STR(opline->op2, lcname);
|
||||
|
||||
if (extends_ast) {
|
||||
opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
|
||||
opline->extended_value = extends_node.u.op.var;
|
||||
} else {
|
||||
opline->opcode = ZEND_DECLARE_CLASS;
|
||||
}
|
||||
|
||||
{
|
||||
zval key;
|
||||
build_runtime_defined_function_key(&key, lcname, decl->lex_pos TSRMLS_CC);
|
||||
opline->op1_type = IS_CONST;
|
||||
opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
|
||||
|
||||
zend_hash_update_ptr(CG(class_table), Z_STR(key), ce);
|
||||
}
|
||||
|
||||
CG(active_class_entry) = ce;
|
||||
|
||||
zend_compile_stmt(stmt_ast TSRMLS_CC);
|
||||
|
||||
// TODO.AST traits, interfaces, extends, etc
|
||||
|
||||
CG(active_class_entry) = NULL;
|
||||
}
|
||||
|
||||
void zend_compile_binary_op(znode *result, zend_ast *ast TSRMLS_DC) {
|
||||
zend_ast *left_ast = ast->child[0];
|
||||
zend_ast *right_ast = ast->child[1];
|
||||
@ -7423,6 +7532,9 @@ void zend_compile_stmt(zend_ast *ast TSRMLS_DC) {
|
||||
case ZEND_AST_USE_TRAIT:
|
||||
zend_compile_use_trait(ast TSRMLS_CC);
|
||||
break;
|
||||
case ZEND_AST_CLASS:
|
||||
zend_compile_class_decl(ast TSRMLS_CC);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
znode result;
|
||||
|
@ -409,18 +409,18 @@ is_variadic:
|
||||
;
|
||||
|
||||
unticked_class_declaration_statement:
|
||||
class_entry_type T_STRING extends_from
|
||||
{ zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
|
||||
implements_list
|
||||
'{'
|
||||
class_statement_list
|
||||
'}' { zend_do_end_class_declaration(&$1, &$3 TSRMLS_CC); }
|
||||
| interface_entry T_STRING
|
||||
class_entry_type T_STRING extends_from implements_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), $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
|
||||
'}' { zend_do_end_class_declaration(&$1, NULL TSRMLS_CC); }
|
||||
'}' { AS($6); zend_do_end_class_declaration(&$1, NULL TSRMLS_CC); }*/
|
||||
;
|
||||
|
||||
|
||||
@ -432,27 +432,22 @@ class_entry_type:
|
||||
;
|
||||
|
||||
extends_from:
|
||||
/* empty */ { $$.op_type = IS_UNUSED; }
|
||||
| T_EXTENDS fully_qualified_class_name { zend_do_fetch_class(&$$, &$2 TSRMLS_CC); }
|
||||
/* 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 */
|
||||
/*interface_extends_list:
|
||||
/* empty /
|
||||
| T_EXTENDS interface_list
|
||||
;
|
||||
;*/
|
||||
|
||||
implements_list:
|
||||
/* empty */
|
||||
| T_IMPLEMENTS interface_list
|
||||
;
|
||||
|
||||
interface_list:
|
||||
fully_qualified_class_name { zend_do_implements_interface(&$1 TSRMLS_CC); }
|
||||
| interface_list ',' fully_qualified_class_name { zend_do_implements_interface(&$3 TSRMLS_CC); }
|
||||
/* empty */ { $$.u.ast = NULL; }
|
||||
| T_IMPLEMENTS name_list { $$.u.ast = $2.u.ast; }
|
||||
;
|
||||
|
||||
foreach_variable:
|
||||
@ -621,23 +616,24 @@ static_var:
|
||||
|
||||
class_statement_list:
|
||||
class_statement_list class_statement
|
||||
{ $$.u.ast = zend_ast_dynamic_add($1.u.ast, $2.u.ast); }
|
||||
| /* empty */
|
||||
{ $$.u.ast = zend_ast_create_dynamic(ZEND_AST_STMT_LIST); }
|
||||
;
|
||||
|
||||
|
||||
class_statement:
|
||||
variable_modifiers property_list ';'
|
||||
{ $$.u.ast = $2.u.ast; $$.u.ast->attr = Z_LVAL($1.u.constant); AS($$); }
|
||||
{ $$.u.ast = $2.u.ast; $$.u.ast->attr = Z_LVAL($1.u.constant); }
|
||||
| class_const_list ';'
|
||||
{ $$.u.ast = $1.u.ast;
|
||||
if (CG(doc_comment)) { STR_RELEASE(CG(doc_comment)); CG(doc_comment) = NULL; }
|
||||
AS($$); }
|
||||
if (CG(doc_comment)) { STR_RELEASE(CG(doc_comment)); CG(doc_comment) = NULL; } }
|
||||
| T_USE name_list trait_adaptations
|
||||
{ $$.u.ast = zend_ast_create_binary(ZEND_AST_USE_TRAIT, $2.u.ast, $3.u.ast); AS($$); }
|
||||
{ $$.u.ast = zend_ast_create_binary(ZEND_AST_USE_TRAIT, $2.u.ast, $3.u.ast); }
|
||||
| method_modifiers function returns_ref T_STRING '(' parameter_list ')' method_body
|
||||
{ $$.u.ast = zend_ast_create_decl(ZEND_AST_METHOD, $3.EA | Z_LVAL($1.u.constant),
|
||||
$2.EA, CG(zend_lineno), LANG_SCNG(yy_text), $2.u.op.ptr,
|
||||
Z_STR($4.u.constant), $6.u.ast, NULL, $8.u.ast); AS($$); }
|
||||
Z_STR($4.u.constant), $6.u.ast, NULL, $8.u.ast); }
|
||||
;
|
||||
|
||||
name_list:
|
||||
|
Loading…
Reference in New Issue
Block a user