Compare commits

..

No commits in common. "aa809cad77144650433d7e9d6a62e5d39322f5e9" and "33d942342176578db98564b421fa448ae8e4b7de" have entirely different histories.

10 changed files with 22124 additions and 19791 deletions

View File

@ -111,7 +111,7 @@ php-parser [flags] <path> ...
Namespace resolver Namespace resolver
------------------ ------------------
Namespace resolver is a visitor that resolves nodes fully qualified name and saves into `map[ast.Vertex]string` structure Namespace resolver is a visitor that resolves nodes fully qualified name and saves into `map[node.Node]string` structure
- For `Class`, `Interface`, `Trait`, `Enum`, `Function`, `Constant` nodes it saves name with current namespace. - For `Class`, `Interface`, `Trait`, `Function`, `Constant` nodes it saves name with current namespace.
- For `Name`, `Relative`, `FullyQualified` nodes it resolves `use` aliases and saves a fully qualified name. - For `Name`, `Relative`, `FullyQualified` nodes it resolves `use` aliases and saves a fully qualified name.

View File

@ -67,24 +67,6 @@ func (lex *Lexer) setTokenPosition(token *token.Token) {
token.Position = pos token.Position = pos
} }
func (lex *Lexer) setTokenPrefixPosition(token *token.Token, n int) {
pos := lex.positionPool.Get()
endPos := lex.ts + n
sl, slb := lex.newLines.GetLine(lex.ts)
el, elb := lex.newLines.GetLine(endPos)
pos.StartLine = sl
pos.EndLine = el
pos.StartPos = lex.ts
pos.EndPos = endPos
pos.StartCol = lex.ts - slb
pos.EndCol = endPos - elb
token.Position = pos
}
func (lex *Lexer) addFreeFloatingToken(t *token.Token, id token.ID, ps, pe int) { func (lex *Lexer) addFreeFloatingToken(t *token.Token, id token.ID, ps, pe int) {
skippedTkn := lex.tokenPool.Get() skippedTkn := lex.tokenPool.Get()
skippedTkn.ID = id skippedTkn.ID = id
@ -216,11 +198,6 @@ func (lex *Lexer) ungetStr(s string) {
} }
} }
func (lex *Lexer) ungetFromStart(n int) {
tokenLength := lex.te - lex.ts
lex.ungetCnt(tokenLength - n)
}
func (lex *Lexer) ungetCnt(n int) { func (lex *Lexer) ungetCnt(n int) {
lex.p = lex.p - n lex.p = lex.p - n
lex.te = lex.te - n lex.te = lex.te - n

View File

@ -4,8 +4,8 @@ package php8
import ( import (
"strconv" "strconv"
"github.com/laytan/php-parser/pkg/ast" "github.com/VKCOM/php-parser/pkg/ast"
"github.com/laytan/php-parser/pkg/token" "github.com/VKCOM/php-parser/pkg/token"
) )
%} %}

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/laytan/php-parser/pkg/token" "github.com/VKCOM/php-parser/pkg/token"
) )
%%{ %%{
@ -240,8 +240,7 @@ func (lex *Lexer) Lex() *token.Token {
'endif'i => {lex.setTokenPosition(tkn); tok = token.T_ENDIF; fbreak;}; 'endif'i => {lex.setTokenPosition(tkn); tok = token.T_ENDIF; fbreak;};
'endswitch'i => {lex.setTokenPosition(tkn); tok = token.T_ENDSWITCH; fbreak;}; 'endswitch'i => {lex.setTokenPosition(tkn); tok = token.T_ENDSWITCH; fbreak;};
'endwhile'i => {lex.setTokenPosition(tkn); tok = token.T_ENDWHILE; fbreak;}; 'endwhile'i => {lex.setTokenPosition(tkn); tok = token.T_ENDWHILE; fbreak;};
'enum'i whitespace+ varname_first => {lex.setTokenPrefixPosition(tkn, 4); tok = token.T_ENUM; lex.ungetFromStart(4); fbreak;}; 'enum'i => {lex.setTokenPosition(tkn); tok = token.T_ENUM; fbreak;};
'enum'i whitespace+ ('extends'i | 'implements'i) => {lex.setTokenPrefixPosition(tkn, 4); tok = token.T_STRING; lex.ungetFromStart(4); fbreak;};
'eval'i => {lex.setTokenPosition(tkn); tok = token.T_EVAL; fbreak;}; 'eval'i => {lex.setTokenPosition(tkn); tok = token.T_EVAL; fbreak;};
'exit'i | 'die'i => {lex.setTokenPosition(tkn); tok = token.T_EXIT; fbreak;}; 'exit'i | 'die'i => {lex.setTokenPosition(tkn); tok = token.T_EXIT; fbreak;};
'extends'i => {lex.setTokenPosition(tkn); tok = token.T_EXTENDS; fbreak;}; 'extends'i => {lex.setTokenPosition(tkn); tok = token.T_EXTENDS; fbreak;};

View File

@ -181,31 +181,6 @@ func TestEnumTokens(t *testing.T) {
suite.Run() suite.Run()
} }
func TestClassNameEnum(t *testing.T) {
suite := tester.NewLexerTokenStructTestSuite(t)
suite.UsePHP8()
suite.Code = "<?php class Enum {}"
suite.Expected = []*token.Token{
{
ID: token.T_CLASS,
Value: []byte("class"),
},
{
ID: token.T_STRING,
Value: []byte("Enum"),
},
{
ID: '{',
Value: []byte("{"),
},
{
ID: '}',
Value: []byte("}"),
},
}
suite.Run()
}
func TestAmpersandFollowedByEllipsisTokens(t *testing.T) { func TestAmpersandFollowedByEllipsisTokens(t *testing.T) {
suite := tester.NewLexerTokenStructTestSuite(t) suite := tester.NewLexerTokenStructTestSuite(t)
suite.UsePHP8() suite.UsePHP8()

View File

@ -89,22 +89,6 @@ func (nsr *NamespaceResolver) StmtClass(n *ast.StmtClass) {
} }
} }
func (nsr *NamespaceResolver) StmtEnum(n *ast.StmtEnum) {
if n.Type != nil {
nsr.ResolveName(n.Type, "")
}
if n.Implements != nil {
for _, interfaceName := range n.Implements {
nsr.ResolveName(interfaceName, "")
}
}
if n.Name != nil {
nsr.AddNamespacedName(n, string(n.Name.(*ast.Identifier).Value))
}
}
func (nsr *NamespaceResolver) StmtInterface(n *ast.StmtInterface) { func (nsr *NamespaceResolver) StmtInterface(n *ast.StmtInterface) {
if n.Extends != nil { if n.Extends != nil {
for _, interfaceName := range n.Extends { for _, interfaceName := range n.Extends {
@ -222,10 +206,6 @@ func (nsr *NamespaceResolver) StmtTraitUse(n *ast.StmtTraitUse) {
} }
} }
func (nsr *NamespaceResolver) Attribute(n *ast.Attribute) {
nsr.ResolveName(n.Name, "")
}
// LeaveNode is invoked after node process // LeaveNode is invoked after node process
func (nsr *NamespaceResolver) LeaveNode(n ast.Vertex) { func (nsr *NamespaceResolver) LeaveNode(n ast.Vertex) {
switch nn := n.(type) { switch nn := n.(type) {
@ -278,16 +258,6 @@ func (nsr *NamespaceResolver) ResolveType(n ast.Vertex) {
switch nn := n.(type) { switch nn := n.(type) {
case *ast.Nullable: case *ast.Nullable:
nsr.ResolveType(nn.Expr) nsr.ResolveType(nn.Expr)
case *ast.Union:
for _, nnn := range nn.Types {
nsr.ResolveType(nnn)
}
case *ast.Intersection:
for _, nnn := range nn.Types {
nsr.ResolveType(nnn)
}
case *ast.Name: case *ast.Name:
nsr.ResolveName(n, "") nsr.ResolveName(n, "")
case *ast.NameRelative: case *ast.NameRelative:
@ -370,12 +340,6 @@ func (ns *Namespace) ResolveName(nameNode ast.Vertex, aliasType string) (string,
case "iterable": case "iterable":
fallthrough fallthrough
case "object": case "object":
fallthrough
case "mixed": // 8.0
fallthrough
case "never": // 8.1
fallthrough
case "true", "false", "null": // 8.2
return part, nil return part, nil
} }
} }

View File

@ -1,10 +1,9 @@
package nsresolver_test package nsresolver_test
import ( import (
"testing"
"github.com/laytan/php-parser/pkg/visitor/nsresolver" "github.com/laytan/php-parser/pkg/visitor/nsresolver"
"github.com/laytan/php-parser/pkg/visitor/traverser" "github.com/laytan/php-parser/pkg/visitor/traverser"
"testing"
"gotest.tools/assert" "gotest.tools/assert"
@ -385,7 +384,6 @@ func TestResolveTraitUse(t *testing.T) {
func TestResolveClassName(t *testing.T) { func TestResolveClassName(t *testing.T) {
nameAB := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("A")}, &ast.NamePart{Value: []byte("B")}}} nameAB := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("A")}, &ast.NamePart{Value: []byte("B")}}}
nameBC := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("B")}, &ast.NamePart{Value: []byte("C")}}} nameBC := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("B")}, &ast.NamePart{Value: []byte("C")}}}
nameCD := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("C")}, &ast.NamePart{Value: []byte("D")}}}
class := &ast.StmtClass{ class := &ast.StmtClass{
Name: &ast.Identifier{Value: []byte("A")}, Name: &ast.Identifier{Value: []byte("A")},
@ -393,13 +391,6 @@ func TestResolveClassName(t *testing.T) {
Implements: []ast.Vertex{ Implements: []ast.Vertex{
nameBC, nameBC,
}, },
AttrGroups: []ast.Vertex{
&ast.AttributeGroup{
Attrs: []ast.Vertex{
&ast.Attribute{Name: nameCD},
},
},
},
} }
stxTree := &ast.StmtStmtList{ stxTree := &ast.StmtStmtList{
@ -412,7 +403,6 @@ func TestResolveClassName(t *testing.T) {
class: "A", class: "A",
nameAB: "A\\B", nameAB: "A\\B",
nameBC: "B\\C", nameBC: "B\\C",
nameCD: "C\\D",
} }
nsResolver := nsresolver.NewNamespaceResolver() nsResolver := nsresolver.NewNamespaceResolver()
@ -473,36 +463,6 @@ func TestResolveTraitName(t *testing.T) {
assert.DeepEqual(t, expected, nsResolver.ResolvedNames) assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
} }
func TestResolveEnumName(t *testing.T) {
nameAB := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("A")}, &ast.NamePart{Value: []byte("B")}}}
nameBC := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("B")}, &ast.NamePart{Value: []byte("C")}}}
enum := &ast.StmtEnum{
Name: &ast.Identifier{Value: []byte("A")},
Type: nameAB,
Implements: []ast.Vertex{
nameBC,
},
}
stxTree := &ast.StmtStmtList{
Stmts: []ast.Vertex{
enum,
},
}
expected := map[ast.Vertex]string{
enum: "A",
nameAB: "A\\B",
nameBC: "B\\C",
}
nsResolver := nsresolver.NewNamespaceResolver()
traverser.NewTraverser(nsResolver).Traverse(stxTree)
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveFunctionName(t *testing.T) { func TestResolveFunctionName(t *testing.T) {
nameAB := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("A")}, &ast.NamePart{Value: []byte("B")}}} nameAB := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("A")}, &ast.NamePart{Value: []byte("B")}}}
nameBC := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("B")}, &ast.NamePart{Value: []byte("C")}}} nameBC := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("B")}, &ast.NamePart{Value: []byte("C")}}}
@ -540,10 +500,6 @@ func TestResolveFunctionName(t *testing.T) {
func TestResolveMethodName(t *testing.T) { func TestResolveMethodName(t *testing.T) {
nameAB := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("A")}, &ast.NamePart{Value: []byte("B")}}} nameAB := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("A")}, &ast.NamePart{Value: []byte("B")}}}
nameBC := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("B")}, &ast.NamePart{Value: []byte("C")}}} nameBC := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("B")}, &ast.NamePart{Value: []byte("C")}}}
nameCD := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("C")}, &ast.NamePart{Value: []byte("D")}}}
nameDE := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("D")}, &ast.NamePart{Value: []byte("E")}}}
nameEF := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("E")}, &ast.NamePart{Value: []byte("F")}}}
nameFG := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("F")}, &ast.NamePart{Value: []byte("G")}}}
methodNode := &ast.StmtClassMethod{ methodNode := &ast.StmtClassMethod{
Name: &ast.Identifier{Value: []byte("A")}, Name: &ast.Identifier{Value: []byte("A")},
@ -552,14 +508,6 @@ func TestResolveMethodName(t *testing.T) {
Type: nameAB, Type: nameAB,
Var: &ast.ExprVariable{Name: &ast.Identifier{Value: []byte("foo")}}, Var: &ast.ExprVariable{Name: &ast.Identifier{Value: []byte("foo")}},
}, },
&ast.Parameter{
Type: &ast.Union{Types: []ast.Vertex{nameCD, nameDE}},
Var: &ast.ExprVariable{Name: &ast.Identifier{Value: []byte("all")}},
},
&ast.Parameter{
Type: &ast.Intersection{Types: []ast.Vertex{nameEF, nameFG}},
Var: &ast.ExprVariable{Name: &ast.Identifier{Value: []byte("any")}},
},
}, },
ReturnType: &ast.Nullable{Expr: nameBC}, ReturnType: &ast.Nullable{Expr: nameBC},
Stmt: &ast.StmtStmtList{ Stmt: &ast.StmtStmtList{
@ -570,10 +518,6 @@ func TestResolveMethodName(t *testing.T) {
expected := map[ast.Vertex]string{ expected := map[ast.Vertex]string{
nameAB: "A\\B", nameAB: "A\\B",
nameBC: "B\\C", nameBC: "B\\C",
nameCD: "C\\D",
nameDE: "D\\E",
nameEF: "E\\F",
nameFG: "F\\G",
} }
nsResolver := nsresolver.NewNamespaceResolver() nsResolver := nsresolver.NewNamespaceResolver()
@ -654,19 +598,6 @@ func TestResolveNamespaces(t *testing.T) {
nameFG := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("F")}, &ast.NamePart{Value: []byte("G")}}} nameFG := &ast.Name{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("F")}, &ast.NamePart{Value: []byte("G")}}}
relativeNameCE := &ast.NameRelative{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("C")}, &ast.NamePart{Value: []byte("E")}}} relativeNameCE := &ast.NameRelative{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("C")}, &ast.NamePart{Value: []byte("E")}}}
relativeNameCA := &ast.NameRelative{Parts: []ast.Vertex{&ast.NamePart{Value: []byte("C")}, &ast.NamePart{Value: []byte("A")}}}
classA := &ast.StmtClass{
Name: &ast.Identifier{Value: []byte("A")},
AttrGroups: []ast.Vertex{
&ast.AttributeGroup{
Attrs: []ast.Vertex{
&ast.Attribute{Name: relativeNameCA},
},
},
},
}
constantB := &ast.StmtConstant{ constantB := &ast.StmtConstant{
Name: &ast.Identifier{Value: []byte("B")}, Name: &ast.Identifier{Value: []byte("B")},
Expr: &ast.ScalarLnumber{Value: []byte("1")}, Expr: &ast.ScalarLnumber{Value: []byte("1")},
@ -681,9 +612,6 @@ func TestResolveNamespaces(t *testing.T) {
&ast.StmtNamespace{ &ast.StmtNamespace{
Name: namespaceAB, Name: namespaceAB,
}, },
classA,
&ast.StmtConstList{ &ast.StmtConstList{
Consts: []ast.Vertex{ Consts: []ast.Vertex{
constantB, constantB,
@ -694,7 +622,6 @@ func TestResolveNamespaces(t *testing.T) {
Class: nameFG, Class: nameFG,
Call: &ast.Identifier{Value: []byte("foo")}, Call: &ast.Identifier{Value: []byte("foo")},
}, },
&ast.StmtNamespace{ &ast.StmtNamespace{
Stmts: []ast.Vertex{}, Stmts: []ast.Vertex{},
}, },
@ -722,8 +649,6 @@ func TestResolveNamespaces(t *testing.T) {
} }
expected := map[ast.Vertex]string{ expected := map[ast.Vertex]string{
classA: "A\\B\\A",
relativeNameCA: "A\\B\\C\\A",
constantB: "A\\B\\B", constantB: "A\\B\\B",
constantC: "A\\B\\C", constantC: "A\\B\\C",
nameFG: "A\\B\\F\\G", nameFG: "A\\B\\F\\G",
@ -855,36 +780,6 @@ func TestDoNotResolveReservedNames(t *testing.T) {
}, },
} }
nameMixed := &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{Value: []byte("mixed")},
},
}
nameNever := &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{Value: []byte("never")},
},
}
nameTrue := &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{Value: []byte("true")},
},
}
nameFalse := &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{Value: []byte("false")},
},
}
nameNull := &ast.Name{
Parts: []ast.Vertex{
&ast.NamePart{Value: []byte("null")},
},
}
function := &ast.StmtFunction{ function := &ast.StmtFunction{
Name: &ast.Identifier{Value: []byte("bar")}, Name: &ast.Identifier{Value: []byte("bar")},
Params: []ast.Vertex{ Params: []ast.Vertex{
@ -930,36 +825,6 @@ func TestDoNotResolveReservedNames(t *testing.T) {
Name: &ast.Identifier{Value: []byte("Object")}, Name: &ast.Identifier{Value: []byte("Object")},
}, },
}, },
&ast.Parameter{
Type: nameMixed,
Var: &ast.ExprVariable{
Name: &ast.Identifier{Value: []byte("Mixed")},
},
},
&ast.Parameter{
Type: nameNever,
Var: &ast.ExprVariable{
Name: &ast.Identifier{Value: []byte("Never")},
},
},
&ast.Parameter{
Type: nameTrue,
Var: &ast.ExprVariable{
Name: &ast.Identifier{Value: []byte("True")},
},
},
&ast.Parameter{
Type: nameFalse,
Var: &ast.ExprVariable{
Name: &ast.Identifier{Value: []byte("False")},
},
},
&ast.Parameter{
Type: nameNull,
Var: &ast.ExprVariable{
Name: &ast.Identifier{Value: []byte("Null")},
},
},
}, },
} }
@ -985,11 +850,6 @@ func TestDoNotResolveReservedNames(t *testing.T) {
nameVoid: "void", nameVoid: "void",
nameIterable: "iterable", nameIterable: "iterable",
nameObject: "object", nameObject: "object",
nameMixed: "mixed",
nameNever: "never",
nameTrue: "true",
nameFalse: "false",
nameNull: "null",
} }
nsResolver := nsresolver.NewNamespaceResolver() nsResolver := nsresolver.NewNamespaceResolver()

View File

@ -957,7 +957,6 @@ func TestParseAndPrintBreak(t *testing.T) {
} }
func TestParseAndPrintClassMethod(t *testing.T) { func TestParseAndPrintClassMethod(t *testing.T) {
t.Skip("TODO: there should not be a blank line between the comment and method.")
src := `<?php src := `<?php
class Foo { class Foo {
/** /**

View File

@ -965,7 +965,6 @@ func TestParseAndPrintBreakPHP8(t *testing.T) {
} }
func TestParseAndPrintClassMethodPHP8(t *testing.T) { func TestParseAndPrintClassMethodPHP8(t *testing.T) {
t.Skip("TODO: there should not be a blank line between the comment and method.")
src := `<?php src := `<?php
class Foo { class Foo {
/** /**