Skip to content

Added support for keywords for class/method/label/declare/namespace/class const names #438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions Zend/tests/bug43343.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
Bug #43343 (Variable class name)
--FILE--
<?php
namespace Foo;
class Bar { }
class if {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why replace a working test with something completely different? If we need to test for if as class name, we can add different test, but that's not what this test was about.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smalyshev actually a class named namespace is supported. So the test was superfluous in it's old state.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bwoebi if it's supported, change the outcome of the test, why rewrite it to something completely different testing something else not related to the bug?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smalyshev good question… Don't remember why I had changed the test. Reverted test now and updated expectf to match actual state.

public static $bar = "if";
}
$foo = 'bar';
var_dump(new namespace::$foo);
var_dump(new if::$$foo);
?>
--EXPECTF--
Parse error: %s error%sexpecting%sT_NS_SEPARATOR%sin %sbug43343.php on line 5
object(if)#1 (0) {
}
59 changes: 59 additions & 0 deletions Zend/tests/identifier_or_keyword.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
--TEST--
Basic keyword support
--FILE--
<?php

class return {
const finally = 1;

public $catch = 1;
}

class yield {
public function __toString() {
return 1;
}

public static function default () {
}

public function namespace () {
}
}

yield::default();

switch (return::finally) {
case (new return)->catch:
case new yield:
echo "O";
default:
goto try;
}
echo "goto T_TRY failed";
try:

(new yield)->namespace();

interface global {}

class abstract extends namespace\yield implements \global {
public function __construct (array $array, callable $call) {
}
}

if (new abstract(["array_arg"], function () {})) {
echo "k";

// Test if it doesn't throw a parse error. fatal error is normal.
// inner_keyword
interface function extends const, break, continue, goto, echo, throw, if, do, for, foreach, declare, instanceof, as, switch, print, class, interface, while, trait, extends, implements, new, clone, var, eval, include, require, use, insteadof, isset, empty, abstract, final, private, protected, public, unset, list, array, callable, or, and, xor {}

// keyword
$obj->elseif->endif->else->endwhile->endfor->endforeach->enddeclare->endswitch->case->exit;
}

?>
--EXPECTF--
Ok
Fatal error: %s in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/lsb_006.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ class Foo extends static {
?>
==DONE==
--EXPECTF--
Parse error: %s error,%sexpecting %s in %s on line %d
Fatal error: Cannot use 'static' as class name as it is reserved in %s on line %d

2 changes: 1 addition & 1 deletion Zend/tests/lsb_007.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ class Foo implements static {
?>
==DONE==
--EXPECTF--
Parse error: %s error,%sexpecting %s in %s on line %d
Fatal error: Cannot use 'static' as interface name as it is reserved in %s on line %d

3 changes: 2 additions & 1 deletion Zend/tests/lsb_008.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ZE2 Late Static Binding class name "static"
<?php
class static {
}
?>
--EXPECTF--
Parse error: %s error,%sexpecting %s in %s on line %d
Fatal error: Cannot use 'static' as class name as it is reserved in %s on line %d

3 changes: 2 additions & 1 deletion Zend/tests/lsb_009.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ZE2 Late Static Binding interface name "static"
<?php
interface static {
}
?>
--EXPECTF--
Parse error: %s error,%sexpecting %s in %s on line %d
Fatal error: Cannot use 'static' as interface name as it is reserved in %s on line %d

19 changes: 0 additions & 19 deletions Zend/tests/traits/error_013.phpt

This file was deleted.

15 changes: 0 additions & 15 deletions Zend/tests/traits/language018.phpt

This file was deleted.

15 changes: 0 additions & 15 deletions Zend/tests/traits/language019.phpt

This file was deleted.

29 changes: 21 additions & 8 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */
zend_stack_init(&CG(context_stack));

CG(encoding_declared) = 0;
CG(tokenbufptr) = -1;
CG(tokenbuffer) = emalloc(sizeof(token_buf) * ((CG(tokenbufsize) = ZEND_INIT_TOKEN_BUF_SIZE) + 1));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to be clever here. Why not just assign CG(tokenbufsize) = ZEND_INIT_TOKEN_BUF_SIZE separately? It would be much more readable.

CG(tokenbuffer)++->token = 0;
CG(tokenbuf_in_class) = -1;
CG(tokenbuf_fn_decl) = -1;
}
/* }}} */

Expand Down Expand Up @@ -236,6 +241,7 @@ void shutdown_compiler(TSRMLS_D) /* {{{ */
zend_hash_destroy(&CG(filenames_table));
zend_llist_destroy(&CG(open_files));
zend_stack_destroy(&CG(context_stack));
efree(--CG(tokenbuffer));
}
/* }}} */

Expand Down Expand Up @@ -4943,9 +4949,13 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name

lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));

if (!(strcmp(lcname, "self") && strcmp(lcname, "parent"))) {
if (!(strcmp(lcname, "self") && strcmp(lcname, "parent") && strcmp(lcname, "static"))) {
efree(lcname);
zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", Z_STRVAL(class_name->u.constant));
if (parent_class_name) {
zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", Z_STRVAL(class_name->u.constant));
} else {
zend_error(E_COMPILE_ERROR, "Cannot use '%s' as interface name as it is reserved", Z_STRVAL(class_name->u.constant));
}
}

/* Class name must not conflict with import names */
Expand Down Expand Up @@ -6735,7 +6745,6 @@ int zendlex(znode *zendlval TSRMLS_DC) /* {{{ */
}

again:
Z_TYPE(zendlval->u.constant) = IS_LONG;
retval = lex_scan(&zendlval->u.constant TSRMLS_CC);
switch (retval) {
case T_COMMENT:
Expand Down Expand Up @@ -6932,9 +6941,11 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC
if (name) {
lcname = zend_str_tolower_dup(Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant));
if (((Z_STRLEN(name->u.constant) == sizeof("self")-1) &&
!memcmp(lcname, "self", sizeof("self")-1)) ||
!memcmp(lcname, "self", sizeof("self")-1)) ||
((Z_STRLEN(name->u.constant) == sizeof("parent")-1) &&
!memcmp(lcname, "parent", sizeof("parent")-1))) {
!memcmp(lcname, "parent", sizeof("parent")-1)) ||
((Z_STRLEN(name->u.constant) == sizeof("static")-1) &&
!memcmp(lcname, "static", sizeof("static")-1))) {
zend_error(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant));
}
efree(lcname);
Expand Down Expand Up @@ -7002,9 +7013,11 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{
lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name));

if (((Z_STRLEN_P(name) == sizeof("self")-1) &&
!memcmp(lcname, "self", sizeof("self")-1)) ||
((Z_STRLEN_P(name) == sizeof("parent")-1) &&
!memcmp(lcname, "parent", sizeof("parent")-1))) {
!memcmp(lcname, "self", sizeof("self")-1)) ||
((Z_STRLEN_P(name) == sizeof("parent")-1) &&
!memcmp(lcname, "parent", sizeof("parent")-1)) ||
((Z_STRLEN_P(name) == sizeof("static")-1) &&
!memcmp(lcname, "static", sizeof("static")-1))) {
zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name));
}

Expand Down
12 changes: 12 additions & 0 deletions Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ typedef struct _zend_compiler_context {
HashTable *labels;
} zend_compiler_context;

typedef struct _token_buf {
zval zv;
int token;
unsigned char *text;
unsigned int len;
unsigned char *start;
unsigned char *end;
char *doc_comment;
zend_uint doc_comment_len;
uint lineno;
} token_buf;

typedef struct _zend_literal {
zval constant;
zend_ulong hash_value;
Expand Down
14 changes: 12 additions & 2 deletions Zend/zend_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ typedef struct _zend_declarables {
typedef struct _zend_vm_stack *zend_vm_stack;
typedef struct _zend_ini_entry zend_ini_entry;


struct _zend_compiler_globals {
zend_stack bp_stack;
zend_stack switch_cond_stack;
Expand Down Expand Up @@ -155,6 +154,13 @@ struct _zend_compiler_globals {
zval ***static_members_table;
int last_static_member;
#endif

token_buf *tokenbuffer;
int tokenbufptr;
int tokenbufsize;
int tokenbuf_in_class;
int tokenbuf_fn_decl;
zend_uchar tokenbuf_mode;
};


Expand Down Expand Up @@ -293,7 +299,7 @@ struct _zend_php_scanner_globals {
int yy_state;
zend_stack state_stack;
zend_ptr_stack heredoc_label_stack;

/* original (unfiltered) script */
unsigned char *script_org;
size_t script_org_size;
Expand All @@ -306,6 +312,10 @@ struct _zend_php_scanner_globals {
zend_encoding_filter input_filter;
zend_encoding_filter output_filter;
const zend_encoding *script_encoding;

/* doc comments */
char *doc_comment;
zend_uint doc_comment_len;
};

#endif /* ZEND_GLOBALS_H */
Expand Down
36 changes: 12 additions & 24 deletions Zend/zend_highlight.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include "zend_highlight.h"
#include "zend_ptr_stack.h"
#include "zend_globals.h"
#include <zend_language_scanner.h>


ZEND_API void zend_html_putc(char c)
{
Expand Down Expand Up @@ -104,10 +106,9 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini
break;
case T_OPEN_TAG:
case T_OPEN_TAG_WITH_ECHO:
next_color = syntax_highlighter_ini->highlight_default;
break;
case T_CLOSE_TAG:
next_color = syntax_highlighter_ini->highlight_default;
Z_TYPE(token) = 0;
break;
case '"':
case T_ENCAPSED_AND_WHITESPACE:
Expand All @@ -116,11 +117,11 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini
break;
case T_WHITESPACE:
zend_html_puts((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng) TSRMLS_CC); /* no color needed */
token.type = 0;
Z_TYPE(token) = 0;
continue;
break;
default:
if (token.type == 0) {
if (Z_TYPE(token) == 0) {
next_color = syntax_highlighter_ini->highlight_keyword;
} else {
next_color = syntax_highlighter_ini->highlight_default;
Expand All @@ -140,21 +141,15 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini

zend_html_puts((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng) TSRMLS_CC);

if (token.type == IS_STRING) {
if (Z_TYPE(token) == IS_STRING) {
switch (token_type) {
case T_OPEN_TAG:
case T_OPEN_TAG_WITH_ECHO:
case T_CLOSE_TAG:
case T_WHITESPACE:
case T_COMMENT:
case T_DOC_COMMENT:
PARSER_IGNORED_TOKEN_CASES
break;
default:
efree(token.value.str.val);
break;
efree(Z_STRVAL(token));
}
}
token.type = 0;
Z_TYPE(token) = 0;
}

if (last_color != syntax_highlighter_ini->highlight_html) {
Expand Down Expand Up @@ -183,7 +178,7 @@ ZEND_API void zend_strip(TSRMLS_D)
case T_DOC_COMMENT:
token.type = 0;
continue;

case T_END_HEREDOC:
zend_write((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
/* read the following character, either newline or ; */
Expand All @@ -202,17 +197,10 @@ ZEND_API void zend_strip(TSRMLS_D)

if (token.type == IS_STRING) {
switch (token_type) {
case T_OPEN_TAG:
case T_OPEN_TAG_WITH_ECHO:
case T_CLOSE_TAG:
case T_WHITESPACE:
case T_COMMENT:
case T_DOC_COMMENT:
PARSER_IGNORED_TOKEN_CASES
break;

default:
efree(token.value.str.val);
break;
efree(Z_STRVAL(token));
}
}
prev_space = token.type = 0;
Expand Down
Loading