Skip to content

Instantly share code, notes, and snippets.

@Tyrael
Created November 21, 2014 17:56
Show Gist options
  • Save Tyrael/2bfa66efbef585ddf9c6 to your computer and use it in GitHub Desktop.
Save Tyrael/2bfa66efbef585ddf9c6 to your computer and use it in GitHub Desktop.
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index d15b85f..03d677a 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -549,6 +549,25 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
}
/* }}} */
+uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */
+{
+ uint32_t new_flags = flags | new_flag;
+ if ((flags & ZEND_ACC_PPP_MASK) && (new_flag & ZEND_ACC_PPP_MASK)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
+ }
+ if ((flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flag & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed");
+ }
+ if ((flags & ZEND_ACC_FINAL_CLASS) && (new_flag & ZEND_ACC_FINAL_CLASS)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Multiple final modifiers are not allowed");
+ }
+ if (((new_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) || (new_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS)) && (new_flags & ZEND_ACC_FINAL_CLASS)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class");
+ }
+ return new_flags;
+}
+/* }}} */
+
uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */
{
uint32_t new_flags = flags | new_flag;
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index f9a66a3..b8ad51d 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -162,7 +162,7 @@ typedef struct _zend_try_catch_element {
#define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS 0x20
#define ZEND_ACC_FINAL_CLASS 0x40
#define ZEND_ACC_INTERFACE 0x80
-#define ZEND_ACC_TRAIT 0x120
+#define ZEND_ACC_TRAIT 0x10000
/* method flags (visibility) */
/* The order of those must be kept - public < protected < private */
@@ -454,6 +454,7 @@ ZEND_API binary_op_type get_binary_op(int opcode);
void zend_stop_lexing(TSRMLS_D);
void zend_emit_final_return(zval *zv TSRMLS_DC);
zend_ast *zend_ast_append_str(zend_ast *left, zend_ast *right);
+uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag);
uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag);
zend_ast *zend_ast_append_doc_comment(zend_ast *list TSRMLS_DC);
void zend_handle_encoding_declaration(zend_ast *ast TSRMLS_DC);
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 8828620..d878ed3 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -255,7 +255,8 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%type <ast> assignment_list
%type <num> returns_ref function is_reference is_variadic class_type variable_modifiers
-%type <num> method_modifiers trait_modifiers non_empty_member_modifiers member_modifier
+%type <num> method_modifiers non_empty_member_modifiers member_modifier
+%type <num> class_modifiers trait_modifiers non_empty_class_modifiers class_modifier
%type <str> backup_doc_comment
@@ -422,20 +423,38 @@ is_variadic:
;
class_declaration_statement:
- class_type { $<num>$ = CG(zend_lineno); }
+ class_modifiers class_type { $<num>$ = CG(zend_lineno); }
T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}'
- { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $<num>2, $6,
- zend_ast_get_str($3), $4, $5, $8); }
- | T_INTERFACE { $<num>$ = CG(zend_lineno); }
+ { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $2 | $1, $<num>3, $7,
+ zend_ast_get_str($4), $5, $6, $9); }
+ | class_modifiers T_INTERFACE { $<num>$ = CG(zend_lineno); }
T_STRING interface_extends_list backup_doc_comment '{' class_statement_list '}'
- { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $<num>2, $5,
- zend_ast_get_str($3), NULL, $4, $7); }
+ { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE | $1, $<num>3, $6,
+ zend_ast_get_str($4), NULL, $5, $8); }
+;
+
+class_modifiers:
+ /* empty */ { $$ = ZEND_ACC_PUBLIC; }
+ | non_empty_class_modifiers
+ { $$ = $1; if (!($$ & ZEND_ACC_PPP_MASK)) { $$ |= ZEND_ACC_PUBLIC; } }
+;
+
+non_empty_class_modifiers:
+ class_modifier { $$ = $1; }
+ | non_empty_class_modifiers class_modifier
+ { $$ = zend_add_class_modifier($1, $2); }
+;
+
+class_modifier:
+ T_PUBLIC { $$ = ZEND_ACC_PUBLIC; }
+ | T_PROTECTED { $$ = ZEND_ACC_PROTECTED; }
+ | T_PRIVATE { $$ = ZEND_ACC_PRIVATE; }
+ | T_ABSTRACT { $$ = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }
+ | T_FINAL { $$ = ZEND_ACC_FINAL_CLASS; }
;
class_type:
T_CLASS { $$ = 0; }
- | T_ABSTRACT T_CLASS { $$ = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }
- | T_FINAL T_CLASS { $$ = ZEND_ACC_FINAL_CLASS; }
| T_TRAIT { $$ = ZEND_ACC_TRAIT; }
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment