php8.1: added readonly modifier (#6)

This commit is contained in:
Makhnev Petr
2021-07-31 18:00:21 +03:00
committed by GitHub
parent 4d0bfa25aa
commit 8c35b0aef1
18 changed files with 7662 additions and 7053 deletions

View File

@@ -899,7 +899,7 @@ func (b *Builder) NewThrowExpr(
func (b *Builder) NewParameter(
AttrGroups []ast.Vertex,
Visibility ast.Vertex,
Modifiers []ast.Vertex,
Type ast.Vertex,
AmpersandTkn *token.Token,
VariadicTkn *token.Token,
@@ -913,8 +913,8 @@ func (b *Builder) NewParameter(
if WithDefault {
if AttrGroups != nil {
pos = b.Pos.NewNodeListNodePosition(AttrGroups, DefaultValue)
} else if Visibility != nil {
pos = b.Pos.NewNodesPosition(Visibility, DefaultValue)
} else if Modifiers != nil {
pos = b.Pos.NewNodeListNodePosition(Modifiers, DefaultValue)
} else if Type != nil {
pos = b.Pos.NewNodesPosition(Type, DefaultValue)
} else if AmpersandTkn != nil {
@@ -927,8 +927,8 @@ func (b *Builder) NewParameter(
} else {
if AttrGroups != nil {
pos = b.Pos.NewNodeListTokenPosition(AttrGroups, VarTkn)
} else if Visibility != nil {
pos = b.Pos.NewNodeTokenPosition(Visibility, VarTkn)
} else if Modifiers != nil {
pos = b.Pos.NewNodeListTokenPosition(Modifiers, VarTkn)
} else if Type != nil {
pos = b.Pos.NewNodeTokenPosition(Type, VarTkn)
} else if AmpersandTkn != nil {
@@ -943,7 +943,7 @@ func (b *Builder) NewParameter(
return &ast.Parameter{
Position: pos,
AttrGroups: AttrGroups,
Visibility: Visibility,
Modifiers: Modifiers,
Type: Type,
AmpersandTkn: AmpersandTkn,
VariadicTkn: VariadicTkn,

View File

@@ -0,0 +1,228 @@
package php8_test
import (
"testing"
"github.com/VKCOM/php-parser/internal/tester"
)
func TestReadonlyModifier(t *testing.T) {
suite := tester.NewParserDumpTestSuite(t)
suite.UsePHP8()
suite.Code = `<?php
class Foo {
readonly string $a;
private readonly string $a;
private string $a;
private readonly $a = 100;
public function __construct(
readonly string $a,
private readonly string $a,
private string $a,
private readonly $a = 100,
) {}
}
`
suite.Expected = `&ast.Root{
Stmts: []ast.Vertex{
&ast.StmtClass{
Name: &ast.Identifier{
Val: []byte("Foo"),
},
Stmts: []ast.Vertex{
&ast.StmtPropertyList{
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("readonly"),
},
},
Type: &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("string"),
},
},
},
Props: []ast.Vertex{
&ast.StmtProperty{
Var: &ast.ExprVariable{
Name: &ast.Identifier{
Val: []byte("$a"),
},
},
},
},
},
&ast.StmtPropertyList{
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("private"),
},
&ast.Identifier{
Val: []byte("readonly"),
},
},
Type: &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("string"),
},
},
},
Props: []ast.Vertex{
&ast.StmtProperty{
Var: &ast.ExprVariable{
Name: &ast.Identifier{
Val: []byte("$a"),
},
},
},
},
},
&ast.StmtPropertyList{
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("private"),
},
},
Type: &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("string"),
},
},
},
Props: []ast.Vertex{
&ast.StmtProperty{
Var: &ast.ExprVariable{
Name: &ast.Identifier{
Val: []byte("$a"),
},
},
},
},
},
&ast.StmtPropertyList{
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("private"),
},
&ast.Identifier{
Val: []byte("readonly"),
},
},
Props: []ast.Vertex{
&ast.StmtProperty{
Var: &ast.ExprVariable{
Name: &ast.Identifier{
Val: []byte("$a"),
},
},
Expr: &ast.ScalarLnumber{
Val: []byte("100"),
},
},
},
},
&ast.StmtClassMethod{
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("public"),
},
},
Name: &ast.Identifier{
Val: []byte("__construct"),
},
Params: []ast.Vertex{
&ast.Parameter{
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("readonly"),
},
},
Type: &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("string"),
},
},
},
Var: &ast.ExprVariable{
Name: &ast.Identifier{
Val: []byte("$a"),
},
},
},
&ast.Parameter{
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("private"),
},
&ast.Identifier{
Val: []byte("readonly"),
},
},
Type: &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("string"),
},
},
},
Var: &ast.ExprVariable{
Name: &ast.Identifier{
Val: []byte("$a"),
},
},
},
&ast.Parameter{
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("private"),
},
},
Type: &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("string"),
},
},
},
Var: &ast.ExprVariable{
Name: &ast.Identifier{
Val: []byte("$a"),
},
},
},
&ast.Parameter{
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("private"),
},
&ast.Identifier{
Val: []byte("readonly"),
},
},
Var: &ast.ExprVariable{
Name: &ast.Identifier{
Val: []byte("$a"),
},
},
DefaultValue: &ast.ScalarLnumber{
Val: []byte("100"),
},
},
},
Stmt: &ast.StmtStmtList{
Stmts: []ast.Vertex{},
},
},
},
},
},
},`
suite.Run()
}

View File

@@ -3883,8 +3883,10 @@ class Point {
},
Params: []ast.Vertex{
&ast.Parameter{
Visibility: &ast.Identifier{
Val: []byte("public"),
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("public"),
},
},
Type: &ast.Name{
Parts: []ast.Vertex{
@@ -3903,8 +3905,10 @@ class Point {
},
},
&ast.Parameter{
Visibility: &ast.Identifier{
Val: []byte("public"),
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("public"),
},
},
Type: &ast.Name{
Parts: []ast.Vertex{
@@ -3923,8 +3927,10 @@ class Point {
},
},
&ast.Parameter{
Visibility: &ast.Identifier{
Val: []byte("public"),
Modifiers: []ast.Vertex{
&ast.Identifier{
Val: []byte("public"),
},
},
Type: &ast.Name{
Parts: []ast.Vertex{
@@ -4057,18 +4063,20 @@ class Point {
},
Params: []ast.Vertex{
&ast.Parameter{
Visibility: &ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
Modifiers: []ast.Vertex{
&ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
},
},
},
Val: []byte("public"),
},
Val: []byte("public"),
},
Var: &ast.ExprVariable{
Name: &ast.Identifier{
@@ -4087,18 +4095,20 @@ class Point {
},
},
&ast.Parameter{
Visibility: &ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
Modifiers: []ast.Vertex{
&ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
},
},
},
Val: []byte("public"),
},
Val: []byte("public"),
},
Type: &ast.Name{
Parts: []ast.Vertex{
@@ -4134,18 +4144,20 @@ class Point {
},
},
&ast.Parameter{
Visibility: &ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
Modifiers: []ast.Vertex{
&ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
},
},
},
Val: []byte("public"),
},
Val: []byte("public"),
},
Type: &ast.Name{
Parts: []ast.Vertex{
@@ -4185,18 +4197,20 @@ class Point {
},
},
&ast.Parameter{
Visibility: &ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
Modifiers: []ast.Vertex{
&ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
},
},
},
Val: []byte("public"),
},
Val: []byte("public"),
},
Type: &ast.Name{
Parts: []ast.Vertex{
@@ -4255,18 +4269,20 @@ class Point {
},
},
&ast.Parameter{
Visibility: &ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
Modifiers: []ast.Vertex{
&ast.Identifier{
IdentifierTkn: &token.Token{
ID: token.T_PUBLIC,
Val: []byte("public"),
FreeFloating: []*token.Token{
{
ID: token.T_WHITESPACE,
Val: []byte("\n "),
},
},
},
Val: []byte("public"),
},
Val: []byte("public"),
},
Type: &ast.Name{
Parts: []ast.Vertex{

File diff suppressed because it is too large Load Diff

View File

@@ -160,6 +160,7 @@ import (
%token <token> T_NAME_RELATIVE
%token <token> T_NAME_QUALIFIED
%token <token> T_NAME_FULLY_QUALIFIED
%token <token> T_READONLY
%token <token> '"'
%token <token> '`'
%token <token> '{'
@@ -223,7 +224,7 @@ import (
%left T_ELSEIF
%left T_ELSE
%left T_ENDIF
%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC T_READONLY
%type <token> optional_arg_ref optional_ellipsis returns_ref
@@ -281,7 +282,7 @@ import (
%type <node> expr_list_allow_comma non_empty_expr_list
%type <node> match match_arm match_arm_list non_empty_match_arm_list
%type <node> catch_list catch
%type <node> optional_visibility_modifier
%type <node> property_modifier
%type <node> attribute_decl attribute_group attribute
%type <node> member_modifier
@@ -293,6 +294,7 @@ import (
%type <list> top_statement_list
%type <list> inner_statement_list class_statement_list
%type <list> method_modifiers variable_modifiers
%type <list> optional_property_modifiers
%type <list> non_empty_member_modifiers class_modifiers optional_class_modifiers
%type <list> optional_attributes attributes
@@ -328,7 +330,8 @@ semi_reserved:
{
$$ = $1
}
| T_STATIC {$$=$1} | T_ABSTRACT {$$=$1} | T_FINAL {$$=$1} | T_PRIVATE {$$=$1} | T_PROTECTED {$$=$1} | T_PUBLIC {$$=$1}
| T_STATIC {$$=$1} | T_ABSTRACT {$$=$1} | T_FINAL {$$=$1} | T_PRIVATE {$$=$1}
| T_PROTECTED {$$=$1} | T_PUBLIC {$$=$1} | T_READONLY {$$=$1}
;
identifier:
@@ -1244,27 +1247,32 @@ alt_if_stmt:
;
parameter_list:
non_empty_parameter_list possible_comma { $$ = yylex.(*Parser).builder.AppendToSeparatedList($1, $2, nil) }
| /* empty */ { $$ = yylex.(*Parser).builder.NewEmptySeparatedList() }
non_empty_parameter_list possible_comma { $$ = yylex.(*Parser).builder.AppendToSeparatedList($1, $2, nil) }
| /* empty */ { $$ = yylex.(*Parser).builder.NewEmptySeparatedList() }
;
non_empty_parameter_list:
parameter { $$ = yylex.(*Parser).builder.NewSeparatedList($1) }
| non_empty_parameter_list ',' parameter { $$ = yylex.(*Parser).builder.AppendToSeparatedList($1, $2, $3) }
parameter { $$ = yylex.(*Parser).builder.NewSeparatedList($1) }
| non_empty_parameter_list ',' parameter { $$ = yylex.(*Parser).builder.AppendToSeparatedList($1, $2, $3) }
;
optional_visibility_modifier:
/* empty */ { $$ = nil; }
| T_PUBLIC { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
| T_PROTECTED { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
| T_PRIVATE { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
optional_property_modifiers:
/* empty */ { $$ = nil }
| optional_property_modifiers property_modifier { $$ = append($1, $2) }
;
property_modifier:
T_PUBLIC { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
| T_PROTECTED { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
| T_PRIVATE { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
| T_READONLY { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
;
parameter:
optional_attributes optional_visibility_modifier optional_type_without_static
optional_attributes optional_property_modifiers optional_type_without_static
optional_arg_ref optional_ellipsis plain_variable
{ $$ = yylex.(*Parser).builder.NewParameter($1, $2, $3, $4, $5, $6, nil, nil, false) }
| optional_attributes optional_visibility_modifier optional_type_without_static
| optional_attributes optional_property_modifiers optional_type_without_static
optional_arg_ref optional_ellipsis plain_variable '=' expr
{ $$ = yylex.(*Parser).builder.NewParameter($1, $2, $3, $4, $5, $6, $7, $8, true) }
;
@@ -1664,6 +1672,7 @@ member_modifier:
| T_STATIC { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
| T_ABSTRACT { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
| T_FINAL { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
| T_READONLY { $$ = yylex.(*Parser).builder.NewIdentifier($1) }
;
property_list:

File diff suppressed because it is too large Load Diff

View File

@@ -252,6 +252,7 @@ func (lex *Lexer) Lex() *token.Token {
'print'i => {lex.setTokenPosition(tkn); tok = token.T_PRINT; fbreak;};
'protected'i => {lex.setTokenPosition(tkn); tok = token.T_PROTECTED; fbreak;};
'return'i => {lex.setTokenPosition(tkn); tok = token.T_RETURN; fbreak;};
'readonly'i => {lex.setTokenPosition(tkn); tok = token.T_READONLY; fbreak;};
'static'i => {lex.setTokenPosition(tkn); tok = token.T_STATIC; fbreak;};
'switch'i => {lex.setTokenPosition(tkn); tok = token.T_SWITCH; fbreak;};
'match'i => {lex.setTokenPosition(tkn); tok = token.T_MATCH; fbreak;};

View File

@@ -0,0 +1,33 @@
package php8_test
import (
"testing"
"github.com/VKCOM/php-parser/internal/tester"
"github.com/VKCOM/php-parser/pkg/token"
)
func TestReadonlyTokens(t *testing.T) {
suite := tester.NewLexerTokenStructTestSuite(t)
suite.UsePHP8()
suite.Code = "<?php readonly public $a;"
suite.Expected = []*token.Token{
{
ID: token.T_READONLY,
Value: []byte("readonly"),
},
{
ID: token.T_PUBLIC,
Value: []byte("public"),
},
{
ID: token.T_VARIABLE,
Value: []byte("$a"),
},
{
ID: ';',
Value: []byte(";"),
},
}
suite.Run()
}