php8.1: added enum (#12)

This commit is contained in:
Makhnev Petr
2021-07-31 19:44:09 +03:00
committed by GitHub
parent 44bbff6073
commit af394e9eb0
18 changed files with 9171 additions and 8531 deletions

View File

@@ -1152,6 +1152,105 @@ func (b *Builder) NewInterface(
return iface
}
func (b *Builder) NewEnumType(
ColonTkn *token.Token,
Type ast.Vertex,
) *ReturnType {
return &ReturnType{
ColonTkn: ColonTkn,
Type: Type,
}
}
func (b *Builder) NewEnumExpr(
AssignTkn *token.Token,
Expr ast.Vertex,
) *EnumCaseExpr {
return &EnumCaseExpr{
AssignTkn: AssignTkn,
Expr: Expr,
}
}
func (b *Builder) NewEnum(
AttrGroups []ast.Vertex,
EnumTkn *token.Token,
Name *token.Token,
EnumScalarType ast.Vertex,
ImplementsList ast.Vertex,
OpenCurlyBracketTkn *token.Token,
Stmts []ast.Vertex,
CloseCurlyBracketTkn *token.Token,
) *ast.StmtEnum {
var pos *position2.Position
if AttrGroups != nil {
pos = b.Pos.NewNodeListTokenPosition(AttrGroups, CloseCurlyBracketTkn)
} else {
pos = b.Pos.NewTokensPosition(EnumTkn, CloseCurlyBracketTkn)
}
enum := &ast.StmtEnum{
Position: pos,
AttrGroups: AttrGroups,
EnumTkn: EnumTkn,
Name: b.NewIdentifier(Name),
OpenCurlyBracketTkn: OpenCurlyBracketTkn,
Stmts: Stmts,
CloseCurlyBracketTkn: CloseCurlyBracketTkn,
}
if EnumScalarType != nil {
enumType := EnumScalarType.(*ReturnType)
enum.ColonTkn = enumType.ColonTkn
enum.Type = enumType.Type
}
if ImplementsList != nil {
enum.ImplementsTkn = ImplementsList.(*ast.StmtClass).ImplementsTkn
enum.Implements = ImplementsList.(*ast.StmtClass).Implements
enum.ImplementsSeparatorTkns = ImplementsList.(*ast.StmtClass).ImplementsSeparatorTkns
}
return enum
}
func (b *Builder) NewEnumCase(
AttrGroups []ast.Vertex,
CaseTkn *token.Token,
Name *token.Token,
Expr ast.Vertex,
SemiColonTkn *token.Token,
) *ast.EnumCase {
var equalTkn *token.Token
var expr ast.Vertex
if Expr != nil {
caseExpr := Expr.(*EnumCaseExpr)
equalTkn = caseExpr.AssignTkn
expr = caseExpr.Expr
}
var pos *position2.Position
if AttrGroups != nil {
pos = b.Pos.NewNodeListTokenPosition(AttrGroups, SemiColonTkn)
} else {
pos = b.Pos.NewTokensPosition(CaseTkn, SemiColonTkn)
}
return &ast.EnumCase{
Position: pos,
CaseTkn: CaseTkn,
AttrGroups: AttrGroups,
Name: b.NewIdentifier(Name),
EqualTkn: equalTkn,
Expr: expr,
SemiColonTkn: SemiColonTkn,
}
}
func (b *Builder) NewFunction(
AttrGroups []ast.Vertex,
FunctionTkn *token.Token,

View File

@@ -68,6 +68,20 @@ func (n *ArgumentList) GetPosition() *position.Position {
return n.Position
}
type EnumCaseExpr struct {
Position *position.Position
AssignTkn *token.Token
Expr ast.Vertex
}
func (n *EnumCaseExpr) Accept(v ast.Visitor) {
// do nothing
}
func (n *EnumCaseExpr) GetPosition() *position.Position {
return n.Position
}
type ReturnType struct {
Position *position.Position
ColonTkn *token.Token

View File

@@ -254,3 +254,71 @@ function f(): never {}
suite.Run()
}
func TestEnum(t *testing.T) {
suite := tester.NewParserDumpTestSuite(t)
suite.UsePHP8()
suite.Code = `<?php
enum A {}
enum B implements Bar, Baz {
}
enum C: int implements Bar {}
`
suite.Expected = `&ast.Root{
Stmts: []ast.Vertex{
&ast.StmtEnum{
Name: &ast.Identifier{
Val: []byte("A"),
},
Stmts: []ast.Vertex{},
},
&ast.StmtEnum{
Name: &ast.Identifier{
Val: []byte("B"),
},
Implements: []ast.Vertex{
&ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("Bar"),
},
},
},
&ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("Baz"),
},
},
},
},
Stmts: []ast.Vertex{},
},
&ast.StmtEnum{
Name: &ast.Identifier{
Val: []byte("C"),
},
Type: &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("int"),
},
},
},
Implements: []ast.Vertex{
&ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{
Val: []byte("Bar"),
},
},
},
},
Stmts: []ast.Vertex{},
},
},
},`
suite.Run()
}

File diff suppressed because it is too large Load Diff

View File

@@ -161,6 +161,7 @@ import (
%token <token> T_NAME_QUALIFIED
%token <token> T_NAME_FULLY_QUALIFIED
%token <token> T_READONLY
%token <token> T_ENUM
%token <token> '"'
%token <token> '`'
%token <token> '{'
@@ -284,6 +285,7 @@ import (
%type <node> catch_list catch
%type <node> property_modifier
%type <node> attribute_decl attribute_group attribute
%type <node> enum_declaration_statement enum_case_expr enum_scalar_type
%type <node> member_modifier
%type <node> foreach_variable
@@ -322,7 +324,7 @@ reserved_non_modifiers:
| T_THROW {$$=$1} | T_USE {$$=$1} | T_INSTEADOF {$$=$1} | T_GLOBAL {$$=$1} | T_VAR {$$=$1} | T_UNSET {$$=$1} | T_ISSET {$$=$1} | T_EMPTY {$$=$1} | T_CONTINUE {$$=$1} | T_GOTO {$$=$1}
| T_FUNCTION {$$=$1} | T_CONST {$$=$1} | T_RETURN {$$=$1} | T_PRINT {$$=$1} | T_YIELD {$$=$1} | T_LIST {$$=$1} | T_SWITCH {$$=$1} | T_ENDSWITCH {$$=$1} | T_CASE {$$=$1} | T_DEFAULT {$$=$1} | T_BREAK {$$=$1}
| T_ARRAY {$$=$1} | T_CALLABLE {$$=$1} | T_EXTENDS {$$=$1} | T_IMPLEMENTS {$$=$1} | T_NAMESPACE {$$=$1} | T_TRAIT {$$=$1} | T_INTERFACE {$$=$1} | T_CLASS {$$=$1}
| T_CLASS_C {$$=$1} | T_TRAIT_C {$$=$1} | T_FUNC_C {$$=$1} | T_METHOD_C {$$=$1} | T_LINE {$$=$1} | T_FILE {$$=$1} | T_DIR {$$=$1} | T_NS_C {$$=$1} | T_FN {$$=$1} | T_MATCH {$$=$1}
| T_CLASS_C {$$=$1} | T_TRAIT_C {$$=$1} | T_FUNC_C {$$=$1} | T_METHOD_C {$$=$1} | T_LINE {$$=$1} | T_FILE {$$=$1} | T_DIR {$$=$1} | T_NS_C {$$=$1} | T_FN {$$=$1} | T_MATCH {$$=$1} | T_ENUM {$$=$1}
;
semi_reserved:
@@ -422,6 +424,7 @@ top_statement:
| class_declaration_statement { $$ = $1 }
| trait_declaration_statement { $$ = $1 }
| interface_declaration_statement { $$ = $1 }
| enum_declaration_statement { $$ = $1 }
| T_HALT_COMPILER '(' ')' ';'
{
$$ = &ast.StmtHaltCompiler{
@@ -540,6 +543,7 @@ inner_statement:
| class_declaration_statement { $$ = $1 }
| trait_declaration_statement { $$ = $1 }
| interface_declaration_statement { $$ = $1 }
| enum_declaration_statement { $$ = $1 }
| T_HALT_COMPILER '(' ')' ';'
{
$$ = &ast.StmtHaltCompiler{
@@ -886,6 +890,20 @@ interface_declaration_statement:
{ $$ = yylex.(*Parser).builder.NewInterface($1, $2, $3, $4, $5, $6, $7) }
;
enum_declaration_statement:
optional_attributes
T_ENUM T_STRING enum_scalar_type implements_list '{' class_statement_list '}'
{ $$ = yylex.(*Parser).builder.NewEnum($1, $2, $3, $4, $5, $6, $7, $8) }
;
enum_scalar_type:
/* empty */ { $$ = nil }
| ':' type { $$ = yylex.(*Parser).builder.NewEnumType($1, $2) }
enum_case_expr:
/* empty */ { $$ = nil }
| '=' expr { $$ = yylex.(*Parser).builder.NewEnumExpr($1, $2) }
extends_from:
/* empty */
{
@@ -1468,6 +1486,8 @@ class_statement:
$$ = traitUse
}
| optional_attributes T_CASE T_STRING enum_case_expr ';'
{ $$ = yylex.(*Parser).builder.NewEnumCase($1, $2, $3, $4, $5) }
;
name_list:

File diff suppressed because it is too large Load Diff

View File

@@ -239,6 +239,7 @@ func (lex *Lexer) Lex() *token.Token {
'endif'i => {lex.setTokenPosition(tkn); tok = token.T_ENDIF; fbreak;};
'endswitch'i => {lex.setTokenPosition(tkn); tok = token.T_ENDSWITCH; fbreak;};
'endwhile'i => {lex.setTokenPosition(tkn); tok = token.T_ENDWHILE; fbreak;};
'enum'i => {lex.setTokenPosition(tkn); tok = token.T_ENUM; fbreak;};
'eval'i => {lex.setTokenPosition(tkn); tok = token.T_EVAL; fbreak;};
'exit'i | 'die'i => {lex.setTokenPosition(tkn); tok = token.T_EXIT; fbreak;};
'extends'i => {lex.setTokenPosition(tkn); tok = token.T_EXTENDS; fbreak;};

View File

@@ -155,3 +155,28 @@ func TestNumberStringTokens(t *testing.T) {
}
suite.Run()
}
func TestEnumTokens(t *testing.T) {
suite := tester.NewLexerTokenStructTestSuite(t)
suite.UsePHP8()
suite.Code = "<?php enum A {}"
suite.Expected = []*token.Token{
{
ID: token.T_ENUM,
Value: []byte("enum"),
},
{
ID: token.T_STRING,
Value: []byte("A"),
},
{
ID: '{',
Value: []byte("{"),
},
{
ID: '}',
Value: []byte("}"),
},
}
suite.Run()
}