}
}
+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];
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;
;
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); }*/
;
;
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:
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: