refactor php7
This commit is contained in:
parent
aab9da03f0
commit
6a84d58ee6
18
Makefile
18
Makefile
@ -22,21 +22,21 @@ bench:
|
||||
go test -benchmem -bench=. ./php5
|
||||
go test -benchmem -bench=. ./php7
|
||||
|
||||
compile: ./php5/php5.go ./php7/php7.go ./scanner/scanner.go fmt
|
||||
sed -i '' -e 's/yyErrorVerbose = false/yyErrorVerbose = true/g' ./php7/php7.go
|
||||
sed -i '' -e 's/yyErrorVerbose = false/yyErrorVerbose = true/g' ./php5/php5.go
|
||||
sed -i '' -e 's/\/\/line/\/\/ line/g' ./php5/php5.go
|
||||
sed -i '' -e 's/\/\/line/\/\/ line/g' ./php7/php7.go
|
||||
sed -i '' -e 's/\/\/line/\/\/ line/g' ./scanner/scanner.go
|
||||
compile: ./internal/php5/php5.go ./internal/php7/php7.go ./internal/scanner/scanner.go fmt
|
||||
sed -i '' -e 's/yyErrorVerbose = false/yyErrorVerbose = true/g' ./internal/php7/php7.go
|
||||
sed -i '' -e 's/yyErrorVerbose = false/yyErrorVerbose = true/g' ./internal/php5/php5.go
|
||||
sed -i '' -e 's/\/\/line/\/\/ line/g' ./internal/php5/php5.go
|
||||
sed -i '' -e 's/\/\/line/\/\/ line/g' ./internal/php7/php7.go
|
||||
sed -i '' -e 's/\/\/line/\/\/ line/g' ./internal/scanner/scanner.go
|
||||
rm -f y.output
|
||||
|
||||
./scanner/scanner.go: ./scanner/scanner.rl
|
||||
./internal/scanner/scanner.go: ./internal/scanner/scanner.rl
|
||||
ragel -Z -G2 -o $@ $<
|
||||
|
||||
./php5/php5.go: ./php5/php5.y
|
||||
./internal/php5/php5.go: ./internal/php5/php5.y
|
||||
goyacc -o $@ $<
|
||||
|
||||
./php7/php7.go: ./php7/php7.y
|
||||
./internal/php7/php7.go: ./internal/php7/php7.y
|
||||
goyacc -o $@ $<
|
||||
|
||||
cpu_pprof:
|
||||
|
@ -1,13 +1,14 @@
|
||||
package php5
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/z7zmey/php-parser/errors"
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/position"
|
||||
"github.com/z7zmey/php-parser/positionbuilder"
|
||||
"strings"
|
||||
|
||||
"github.com/z7zmey/php-parser/internal/positionbuilder"
|
||||
"github.com/z7zmey/php-parser/pkg/ast"
|
||||
"github.com/z7zmey/php-parser/pkg/errors"
|
||||
"github.com/z7zmey/php-parser/pkg/position"
|
||||
"github.com/z7zmey/php-parser/scanner"
|
||||
)
|
||||
|
||||
@ -20,7 +21,7 @@ type Parser struct {
|
||||
Lexer scanner.Scanner
|
||||
currentToken *scanner.Token
|
||||
positionBuilder *positionbuilder.PositionBuilder
|
||||
rootNode node.Node
|
||||
rootNode ast.Vertex
|
||||
}
|
||||
|
||||
// NewParser creates and returns new Parser
|
||||
@ -54,7 +55,7 @@ func (l *Parser) Error(msg string) {
|
||||
l.Lexer.AddError(errors.NewError(msg, pos))
|
||||
}
|
||||
|
||||
func (l *Parser) WithFreeFloating() {
|
||||
func (l *Parser) WithTokens() {
|
||||
l.Lexer.SetWithFreeFloating(true)
|
||||
}
|
||||
|
||||
@ -71,7 +72,7 @@ func (l *Parser) Parse() int {
|
||||
}
|
||||
|
||||
// GetRootNode returns root node
|
||||
func (l *Parser) GetRootNode() node.Node {
|
||||
func (l *Parser) GetRootNode() ast.Vertex {
|
||||
return l.rootNode
|
||||
}
|
||||
|
190
internal/php7/parser.go
Normal file
190
internal/php7/parser.go
Normal file
@ -0,0 +1,190 @@
|
||||
package php7
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/z7zmey/php-parser/internal/positionbuilder"
|
||||
"github.com/z7zmey/php-parser/internal/scanner"
|
||||
"github.com/z7zmey/php-parser/pkg/ast"
|
||||
"github.com/z7zmey/php-parser/pkg/errors"
|
||||
"github.com/z7zmey/php-parser/pkg/position"
|
||||
"github.com/z7zmey/php-parser/pkg/token"
|
||||
)
|
||||
|
||||
func (lval *yySymType) Token(t *scanner.Token) {
|
||||
lval.token = t
|
||||
}
|
||||
|
||||
// Parser structure
|
||||
type Parser struct {
|
||||
Lexer scanner.Scanner
|
||||
currentToken *scanner.Token
|
||||
positionBuilder *positionbuilder.PositionBuilder
|
||||
rootNode ast.Vertex
|
||||
}
|
||||
|
||||
// NewParser creates and returns new Parser
|
||||
func NewParser(src []byte, v string) *Parser {
|
||||
lexer := scanner.NewLexer(src)
|
||||
lexer.PHPVersion = v
|
||||
|
||||
return &Parser{
|
||||
lexer,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Parser) Lex(lval *yySymType) int {
|
||||
t := l.Lexer.Lex(lval)
|
||||
l.currentToken = lval.token
|
||||
return t
|
||||
}
|
||||
|
||||
func (l *Parser) Error(msg string) {
|
||||
pos := &position.Position{
|
||||
StartLine: l.currentToken.StartLine,
|
||||
EndLine: l.currentToken.EndLine,
|
||||
StartPos: l.currentToken.StartPos,
|
||||
EndPos: l.currentToken.EndPos,
|
||||
}
|
||||
|
||||
l.Lexer.AddError(errors.NewError(msg, pos))
|
||||
}
|
||||
|
||||
func (l *Parser) WithTokens() {
|
||||
l.Lexer.SetWithTokens(true)
|
||||
}
|
||||
|
||||
// Parse the php7 Parser entrypoint
|
||||
func (l *Parser) Parse() int {
|
||||
// init
|
||||
l.Lexer.SetErrors(nil)
|
||||
l.rootNode = nil
|
||||
l.positionBuilder = &positionbuilder.PositionBuilder{}
|
||||
|
||||
// parse
|
||||
|
||||
return yyParse(l)
|
||||
}
|
||||
|
||||
// GetRootNode returns root node
|
||||
func (l *Parser) GetRootNode() ast.Vertex {
|
||||
return l.rootNode
|
||||
}
|
||||
|
||||
// GetErrors returns errors list
|
||||
func (l *Parser) GetErrors() []*errors.Error {
|
||||
return l.Lexer.GetErrors()
|
||||
}
|
||||
|
||||
// helpers
|
||||
|
||||
func lastNode(nn []ast.Vertex) ast.Vertex {
|
||||
if len(nn) == 0 {
|
||||
return nil
|
||||
}
|
||||
return nn[len(nn)-1]
|
||||
}
|
||||
|
||||
func firstNode(nn []ast.Vertex) ast.Vertex {
|
||||
return nn[0]
|
||||
}
|
||||
|
||||
func isDollar(r rune) bool {
|
||||
return r == '$'
|
||||
}
|
||||
|
||||
func (l *Parser) MoveFreeFloating(src ast.Vertex, dst ast.Vertex) {
|
||||
if l.Lexer.GetWithFreeFloating() == false {
|
||||
return
|
||||
}
|
||||
|
||||
if src.GetNode().Tokens == nil {
|
||||
return
|
||||
}
|
||||
|
||||
l.setFreeFloating(dst, token.Start, src.GetNode().Tokens[token.Start])
|
||||
delete(src.GetNode().Tokens, token.Start)
|
||||
}
|
||||
|
||||
func (l *Parser) setFreeFloating(dst ast.Vertex, p token.Position, strings []token.Token) {
|
||||
if l.Lexer.GetWithFreeFloating() == false {
|
||||
return
|
||||
}
|
||||
|
||||
if len(strings) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
dstCollection := &dst.GetNode().Tokens
|
||||
if *dstCollection == nil {
|
||||
*dstCollection = make(token.Collection)
|
||||
}
|
||||
|
||||
(*dstCollection)[p] = strings
|
||||
}
|
||||
|
||||
func (l *Parser) GetFreeFloatingToken(t *scanner.Token) []token.Token {
|
||||
if l.Lexer.GetWithFreeFloating() == false {
|
||||
return []token.Token{}
|
||||
}
|
||||
|
||||
tokens := make([]token.Token, len(t.Tokens))
|
||||
copy(tokens, t.Tokens)
|
||||
|
||||
return tokens
|
||||
}
|
||||
|
||||
func (l *Parser) splitSemiColonAndPhpCloseTag(htmlNode ast.Vertex, prevNode ast.Vertex) {
|
||||
if l.Lexer.GetWithFreeFloating() == false {
|
||||
return
|
||||
}
|
||||
|
||||
semiColon := prevNode.GetNode().Tokens[token.SemiColon]
|
||||
delete(prevNode.GetNode().Tokens, token.SemiColon)
|
||||
if len(semiColon) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if semiColon[0].Value[0] == ';' {
|
||||
l.setFreeFloating(prevNode, token.SemiColon, []token.Token{
|
||||
{
|
||||
ID: token.ID(';'),
|
||||
Value: semiColon[0].Value[0:1],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
vlen := len(semiColon[0].Value)
|
||||
tlen := 2
|
||||
if bytes.HasSuffix(semiColon[0].Value, []byte("?>\n")) {
|
||||
tlen = 3
|
||||
}
|
||||
|
||||
phpCloseTag := []token.Token{}
|
||||
if vlen-tlen > 1 {
|
||||
phpCloseTag = append(phpCloseTag, token.Token{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: semiColon[0].Value[1 : vlen-tlen],
|
||||
})
|
||||
}
|
||||
|
||||
phpCloseTag = append(phpCloseTag, token.Token{
|
||||
ID: T_CLOSE_TAG,
|
||||
Value: semiColon[0].Value[vlen-tlen:],
|
||||
})
|
||||
|
||||
l.setFreeFloating(htmlNode, token.Start, append(phpCloseTag, htmlNode.GetNode().Tokens[token.Start]...))
|
||||
}
|
||||
|
||||
func (p *Parser) returnTokenToPool(yyDollar []yySymType, yyVAL *yySymType) {
|
||||
for i := 1; i < len(yyDollar); i++ {
|
||||
if yyDollar[i].token != nil {
|
||||
p.Lexer.ReturnTokenToPool(yyDollar[i].token)
|
||||
}
|
||||
yyDollar[i].token = nil
|
||||
}
|
||||
yyVAL.token = nil
|
||||
}
|
Binary file not shown.
5655
internal/php7/php7.y
Normal file
5655
internal/php7/php7.y
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ package php7_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/z7zmey/php-parser/php7"
|
||||
"github.com/z7zmey/php-parser/internal/php7"
|
||||
)
|
||||
|
||||
func BenchmarkPhp7(b *testing.B) {
|
20023
internal/php7/php7_test.go
Normal file
20023
internal/php7/php7_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,9 @@
|
||||
package positionbuilder
|
||||
|
||||
import (
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/position"
|
||||
"github.com/z7zmey/php-parser/scanner"
|
||||
"github.com/z7zmey/php-parser/internal/scanner"
|
||||
"github.com/z7zmey/php-parser/pkg/ast"
|
||||
"github.com/z7zmey/php-parser/pkg/position"
|
||||
)
|
||||
|
||||
// PositionBuilder provide functions to constuct positions
|
||||
@ -19,7 +19,7 @@ type endPos struct {
|
||||
endPos int
|
||||
}
|
||||
|
||||
func (b *PositionBuilder) getListStartPos(l []node.Node) startPos {
|
||||
func (b *PositionBuilder) getListStartPos(l []ast.Vertex) startPos {
|
||||
if l == nil {
|
||||
return startPos{-1, -1}
|
||||
}
|
||||
@ -31,7 +31,7 @@ func (b *PositionBuilder) getListStartPos(l []node.Node) startPos {
|
||||
return b.getNodeStartPos(l[0])
|
||||
}
|
||||
|
||||
func (b *PositionBuilder) getNodeStartPos(n node.Node) startPos {
|
||||
func (b *PositionBuilder) getNodeStartPos(n ast.Vertex) startPos {
|
||||
sl := -1
|
||||
sp := -1
|
||||
|
||||
@ -39,7 +39,7 @@ func (b *PositionBuilder) getNodeStartPos(n node.Node) startPos {
|
||||
return startPos{-1, -1}
|
||||
}
|
||||
|
||||
p := n.GetPosition()
|
||||
p := n.GetNode().Position
|
||||
if p != nil {
|
||||
sl = p.StartLine
|
||||
sp = p.StartPos
|
||||
@ -48,7 +48,7 @@ func (b *PositionBuilder) getNodeStartPos(n node.Node) startPos {
|
||||
return startPos{sl, sp}
|
||||
}
|
||||
|
||||
func (b *PositionBuilder) getListEndPos(l []node.Node) endPos {
|
||||
func (b *PositionBuilder) getListEndPos(l []ast.Vertex) endPos {
|
||||
if l == nil {
|
||||
return endPos{-1, -1}
|
||||
}
|
||||
@ -60,7 +60,7 @@ func (b *PositionBuilder) getListEndPos(l []node.Node) endPos {
|
||||
return b.getNodeEndPos(l[len(l)-1])
|
||||
}
|
||||
|
||||
func (b *PositionBuilder) getNodeEndPos(n node.Node) endPos {
|
||||
func (b *PositionBuilder) getNodeEndPos(n ast.Vertex) endPos {
|
||||
el := -1
|
||||
ep := -1
|
||||
|
||||
@ -68,7 +68,7 @@ func (b *PositionBuilder) getNodeEndPos(n node.Node) endPos {
|
||||
return endPos{-1, -1}
|
||||
}
|
||||
|
||||
p := n.GetPosition()
|
||||
p := n.GetNode().Position
|
||||
if p != nil {
|
||||
el = p.EndLine
|
||||
ep = p.EndPos
|
||||
@ -78,7 +78,7 @@ func (b *PositionBuilder) getNodeEndPos(n node.Node) endPos {
|
||||
}
|
||||
|
||||
// NewNodeListPosition returns new Position
|
||||
func (b *PositionBuilder) NewNodeListPosition(list []node.Node) *position.Position {
|
||||
func (b *PositionBuilder) NewNodeListPosition(list []ast.Vertex) *position.Position {
|
||||
return &position.Position{
|
||||
StartLine: b.getListStartPos(list).startLine,
|
||||
EndLine: b.getListEndPos(list).endLine,
|
||||
@ -88,7 +88,7 @@ func (b *PositionBuilder) NewNodeListPosition(list []node.Node) *position.Positi
|
||||
}
|
||||
|
||||
// NewNodePosition returns new Position
|
||||
func (b *PositionBuilder) NewNodePosition(n node.Node) *position.Position {
|
||||
func (b *PositionBuilder) NewNodePosition(n ast.Vertex) *position.Position {
|
||||
return &position.Position{
|
||||
StartLine: b.getNodeStartPos(n).startLine,
|
||||
EndLine: b.getNodeEndPos(n).endLine,
|
||||
@ -118,7 +118,7 @@ func (b *PositionBuilder) NewTokensPosition(startToken *scanner.Token, endToken
|
||||
}
|
||||
|
||||
// NewTokenNodePosition returns new Position
|
||||
func (b *PositionBuilder) NewTokenNodePosition(t *scanner.Token, n node.Node) *position.Position {
|
||||
func (b *PositionBuilder) NewTokenNodePosition(t *scanner.Token, n ast.Vertex) *position.Position {
|
||||
return &position.Position{
|
||||
StartLine: t.StartLine,
|
||||
EndLine: b.getNodeEndPos(n).endLine,
|
||||
@ -128,7 +128,7 @@ func (b *PositionBuilder) NewTokenNodePosition(t *scanner.Token, n node.Node) *p
|
||||
}
|
||||
|
||||
// NewNodeTokenPosition returns new Position
|
||||
func (b *PositionBuilder) NewNodeTokenPosition(n node.Node, t *scanner.Token) *position.Position {
|
||||
func (b *PositionBuilder) NewNodeTokenPosition(n ast.Vertex, t *scanner.Token) *position.Position {
|
||||
return &position.Position{
|
||||
StartLine: b.getNodeStartPos(n).startLine,
|
||||
EndLine: t.EndLine,
|
||||
@ -138,7 +138,7 @@ func (b *PositionBuilder) NewNodeTokenPosition(n node.Node, t *scanner.Token) *p
|
||||
}
|
||||
|
||||
// NewNodesPosition returns new Position
|
||||
func (b *PositionBuilder) NewNodesPosition(startNode node.Node, endNode node.Node) *position.Position {
|
||||
func (b *PositionBuilder) NewNodesPosition(startNode ast.Vertex, endNode ast.Vertex) *position.Position {
|
||||
return &position.Position{
|
||||
StartLine: b.getNodeStartPos(startNode).startLine,
|
||||
EndLine: b.getNodeEndPos(endNode).endLine,
|
||||
@ -148,7 +148,7 @@ func (b *PositionBuilder) NewNodesPosition(startNode node.Node, endNode node.Nod
|
||||
}
|
||||
|
||||
// NewNodeListTokenPosition returns new Position
|
||||
func (b *PositionBuilder) NewNodeListTokenPosition(list []node.Node, t *scanner.Token) *position.Position {
|
||||
func (b *PositionBuilder) NewNodeListTokenPosition(list []ast.Vertex, t *scanner.Token) *position.Position {
|
||||
return &position.Position{
|
||||
StartLine: b.getListStartPos(list).startLine,
|
||||
EndLine: t.EndLine,
|
||||
@ -158,7 +158,7 @@ func (b *PositionBuilder) NewNodeListTokenPosition(list []node.Node, t *scanner.
|
||||
}
|
||||
|
||||
// NewTokenNodeListPosition returns new Position
|
||||
func (b *PositionBuilder) NewTokenNodeListPosition(t *scanner.Token, list []node.Node) *position.Position {
|
||||
func (b *PositionBuilder) NewTokenNodeListPosition(t *scanner.Token, list []ast.Vertex) *position.Position {
|
||||
return &position.Position{
|
||||
StartLine: t.StartLine,
|
||||
EndLine: b.getListEndPos(list).endLine,
|
||||
@ -168,7 +168,7 @@ func (b *PositionBuilder) NewTokenNodeListPosition(t *scanner.Token, list []node
|
||||
}
|
||||
|
||||
// NewNodeNodeListPosition returns new Position
|
||||
func (b *PositionBuilder) NewNodeNodeListPosition(n node.Node, list []node.Node) *position.Position {
|
||||
func (b *PositionBuilder) NewNodeNodeListPosition(n ast.Vertex, list []ast.Vertex) *position.Position {
|
||||
return &position.Position{
|
||||
StartLine: b.getNodeStartPos(n).startLine,
|
||||
EndLine: b.getListEndPos(list).endLine,
|
||||
@ -178,7 +178,7 @@ func (b *PositionBuilder) NewNodeNodeListPosition(n node.Node, list []node.Node)
|
||||
}
|
||||
|
||||
// NewNodeListNodePosition returns new Position
|
||||
func (b *PositionBuilder) NewNodeListNodePosition(list []node.Node, n node.Node) *position.Position {
|
||||
func (b *PositionBuilder) NewNodeListNodePosition(list []ast.Vertex, n ast.Vertex) *position.Position {
|
||||
return &position.Position{
|
||||
StartLine: b.getListStartPos(list).startLine,
|
||||
EndLine: b.getNodeEndPos(n).endLine,
|
||||
@ -188,7 +188,7 @@ func (b *PositionBuilder) NewNodeListNodePosition(list []node.Node, n node.Node)
|
||||
}
|
||||
|
||||
// NewOptionalListTokensPosition returns new Position
|
||||
func (b *PositionBuilder) NewOptionalListTokensPosition(list []node.Node, t *scanner.Token, endToken *scanner.Token) *position.Position {
|
||||
func (b *PositionBuilder) NewOptionalListTokensPosition(list []ast.Vertex, t *scanner.Token, endToken *scanner.Token) *position.Position {
|
||||
if list == nil {
|
||||
return &position.Position{
|
||||
StartLine: t.StartLine,
|
485
internal/positionbuilder/position_builder_test.go
Normal file
485
internal/positionbuilder/position_builder_test.go
Normal file
@ -0,0 +1,485 @@
|
||||
package positionbuilder_test
|
||||
|
||||
import (
|
||||
"gotest.tools/assert"
|
||||
"testing"
|
||||
|
||||
"github.com/z7zmey/php-parser/internal/positionbuilder"
|
||||
"github.com/z7zmey/php-parser/internal/scanner"
|
||||
"github.com/z7zmey/php-parser/pkg/ast"
|
||||
"github.com/z7zmey/php-parser/pkg/position"
|
||||
)
|
||||
|
||||
func TestNewTokenPosition(t *testing.T) {
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
tkn := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
|
||||
pos := builder.NewTokenPosition(tkn)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 1, 0, 3}, pos)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 1, 0, 3}, pos)
|
||||
}
|
||||
|
||||
func TestNewTokensPosition(t *testing.T) {
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
token1 := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
token2 := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 4,
|
||||
EndPos: 6,
|
||||
}
|
||||
|
||||
pos := builder.NewTokensPosition(token1, token2)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 2, 0, 6}, pos)
|
||||
}
|
||||
|
||||
func TestNewNodePosition(t *testing.T) {
|
||||
n := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodePosition(n)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 1, 0, 3}, pos)
|
||||
}
|
||||
|
||||
func TestNewTokenNodePosition(t *testing.T) {
|
||||
tkn := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
n := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 4,
|
||||
EndPos: 12,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewTokenNodePosition(tkn, n)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 2, 0, 12}, pos)
|
||||
}
|
||||
|
||||
func TestNewNodeTokenPosition(t *testing.T) {
|
||||
n := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 9,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tkn := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 10,
|
||||
EndPos: 12,
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeTokenPosition(n, tkn)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 2, 0, 12}, pos)
|
||||
}
|
||||
|
||||
func TestNewNodeListPosition(t *testing.T) {
|
||||
n1 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 9,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
n2 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 10,
|
||||
EndPos: 19,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListPosition([]ast.Vertex{n1, n2})
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 2, 0, 19}, pos)
|
||||
}
|
||||
|
||||
func TestNewNodesPosition(t *testing.T) {
|
||||
n1 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 9,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
n2 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 10,
|
||||
EndPos: 19,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodesPosition(n1, n2)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 2, 0, 19}, pos)
|
||||
}
|
||||
|
||||
func TestNewNodeListTokenPosition(t *testing.T) {
|
||||
n1 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 9,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
n2 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 10,
|
||||
EndPos: 19,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tkn := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 20,
|
||||
EndPos: 22,
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListTokenPosition([]ast.Vertex{n1, n2}, tkn)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 3, 0, 22}, pos)
|
||||
}
|
||||
|
||||
func TestNewTokenNodeListPosition(t *testing.T) {
|
||||
tkn := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 2,
|
||||
}
|
||||
|
||||
n1 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 3,
|
||||
EndPos: 10,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
n2 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 11,
|
||||
EndPos: 20,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewTokenNodeListPosition(tkn, []ast.Vertex{n1, n2})
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 3, 0, 20}, pos)
|
||||
}
|
||||
|
||||
func TestNewNodeNodeListPosition(t *testing.T) {
|
||||
n1 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 8,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
n2 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 9,
|
||||
EndPos: 17,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
n3 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 18,
|
||||
EndPos: 26,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeNodeListPosition(n1, []ast.Vertex{n2, n3})
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 3, 0, 26}, pos)
|
||||
}
|
||||
|
||||
func TestNewNodeListNodePosition(t *testing.T) {
|
||||
n1 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 8,
|
||||
},
|
||||
},
|
||||
}
|
||||
n2 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 9,
|
||||
EndPos: 17,
|
||||
},
|
||||
},
|
||||
}
|
||||
n3 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 18,
|
||||
EndPos: 26,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListNodePosition([]ast.Vertex{n1, n2}, n3)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 3, 0, 26}, pos)
|
||||
}
|
||||
|
||||
func TestNewOptionalListTokensPosition(t *testing.T) {
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
token1 := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
token2 := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 4,
|
||||
EndPos: 6,
|
||||
}
|
||||
|
||||
pos := builder.NewOptionalListTokensPosition(nil, token1, token2)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, 2, 0, 6}, pos)
|
||||
}
|
||||
|
||||
func TestNewOptionalListTokensPosition2(t *testing.T) {
|
||||
n2 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 9,
|
||||
EndPos: 17,
|
||||
},
|
||||
},
|
||||
}
|
||||
n3 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 18,
|
||||
EndPos: 26,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
token1 := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 4,
|
||||
EndLine: 4,
|
||||
StartPos: 27,
|
||||
EndPos: 29,
|
||||
}
|
||||
token2 := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 5,
|
||||
EndLine: 5,
|
||||
StartPos: 30,
|
||||
EndPos: 32,
|
||||
}
|
||||
|
||||
pos := builder.NewOptionalListTokensPosition([]ast.Vertex{n2, n3}, token1, token2)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{2, 5, 9, 32}, pos)
|
||||
}
|
||||
|
||||
func TestNilNodePos(t *testing.T) {
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodesPosition(nil, nil)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{-1, -1, -1, -1}, pos)
|
||||
}
|
||||
|
||||
func TestNilNodeListPos(t *testing.T) {
|
||||
n1 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 8,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeNodeListPosition(n1, nil)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, -1, 0, -1}, pos)
|
||||
}
|
||||
|
||||
func TestNilNodeListTokenPos(t *testing.T) {
|
||||
token := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListTokenPosition(nil, token)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{-1, 1, -1, 3}, pos)
|
||||
}
|
||||
|
||||
func TestEmptyNodeListPos(t *testing.T) {
|
||||
n1 := &ast.Identifier{
|
||||
Node: ast.Node{
|
||||
Position: &position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 8,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeNodeListPosition(n1, []ast.Vertex{})
|
||||
|
||||
assert.DeepEqual(t, &position.Position{1, -1, 0, -1}, pos)
|
||||
}
|
||||
|
||||
func TestEmptyNodeListTokenPos(t *testing.T) {
|
||||
token := &scanner.Token{
|
||||
Value: []byte(`foo`),
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListTokenPosition([]ast.Vertex{}, token)
|
||||
|
||||
assert.DeepEqual(t, &position.Position{-1, 1, -1, 3}, pos)
|
||||
}
|
@ -4,10 +4,10 @@ import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/z7zmey/php-parser/errors"
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
"github.com/z7zmey/php-parser/position"
|
||||
"github.com/z7zmey/php-parser/version"
|
||||
"github.com/z7zmey/php-parser/internal/version"
|
||||
"github.com/z7zmey/php-parser/pkg/errors"
|
||||
"github.com/z7zmey/php-parser/pkg/position"
|
||||
"github.com/z7zmey/php-parser/pkg/token"
|
||||
)
|
||||
|
||||
type Scanner interface {
|
||||
@ -17,7 +17,7 @@ type Scanner interface {
|
||||
SetPhpDocComment(string)
|
||||
GetErrors() []*errors.Error
|
||||
GetWithFreeFloating() bool
|
||||
SetWithFreeFloating(bool)
|
||||
SetWithTokens(bool)
|
||||
AddError(e *errors.Error)
|
||||
SetErrors(e []*errors.Error)
|
||||
}
|
||||
@ -36,8 +36,8 @@ type Lexer struct {
|
||||
heredocLabel []byte
|
||||
|
||||
TokenPool *TokenPool
|
||||
FreeFloating []freefloating.String
|
||||
WithFreeFloating bool
|
||||
Tokens []token.Token
|
||||
WithTokens bool
|
||||
PhpDocComment string
|
||||
lastToken *Token
|
||||
Errors []*errors.Error
|
||||
@ -62,11 +62,11 @@ func (l *Lexer) GetErrors() []*errors.Error {
|
||||
}
|
||||
|
||||
func (l *Lexer) GetWithFreeFloating() bool {
|
||||
return l.WithFreeFloating
|
||||
return l.WithTokens
|
||||
}
|
||||
|
||||
func (l *Lexer) SetWithFreeFloating(b bool) {
|
||||
l.WithFreeFloating = b
|
||||
func (l *Lexer) SetWithTokens(b bool) {
|
||||
l.WithTokens = b
|
||||
}
|
||||
|
||||
func (l *Lexer) AddError(e *errors.Error) {
|
||||
@ -84,22 +84,14 @@ func (lex *Lexer) setTokenPosition(token *Token) {
|
||||
token.EndPos = lex.te
|
||||
}
|
||||
|
||||
func (lex *Lexer) addFreeFloating(t freefloating.StringType, ps, pe int) {
|
||||
if !lex.WithFreeFloating {
|
||||
func (lex *Lexer) addToken(id TokenID, ps, pe int) {
|
||||
if !lex.WithTokens {
|
||||
return
|
||||
}
|
||||
|
||||
pos := position.NewPosition(
|
||||
lex.NewLines.GetLine(lex.ts),
|
||||
lex.NewLines.GetLine(lex.te-1),
|
||||
lex.ts,
|
||||
lex.te,
|
||||
)
|
||||
|
||||
lex.FreeFloating = append(lex.FreeFloating, freefloating.String{
|
||||
StringType: t,
|
||||
Value: string(lex.data[ps:pe]),
|
||||
Position: pos,
|
||||
lex.Tokens = append(lex.Tokens, token.Token{
|
||||
ID: token.ID(id),
|
||||
Value: lex.data[ps:pe],
|
||||
})
|
||||
}
|
||||
|
Binary file not shown.
@ -4,8 +4,6 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
)
|
||||
|
||||
%%{
|
||||
@ -30,13 +28,13 @@ func NewLexer(data []byte) *Lexer {
|
||||
}
|
||||
|
||||
func (lex *Lexer) Lex(lval Lval) int {
|
||||
lex.FreeFloating = nil
|
||||
lex.Tokens = nil
|
||||
eof := lex.pe
|
||||
var tok TokenID
|
||||
|
||||
token := lex.TokenPool.Get()
|
||||
token.FreeFloating = lex.FreeFloating
|
||||
token.Value = string(lex.data[0:0])
|
||||
token.Tokens = lex.Tokens
|
||||
token.Value = lex.data[0:0]
|
||||
|
||||
lblStart := 0
|
||||
lblEnd := 0
|
||||
@ -136,7 +134,7 @@ func (lex *Lexer) Lex(lval Lval) int {
|
||||
|
||||
main := |*
|
||||
"#!" any* :>> newline => {
|
||||
lex.addFreeFloating(freefloating.CommentType, lex.ts, lex.te)
|
||||
lex.addToken(T_COMMENT, lex.ts, lex.te)
|
||||
};
|
||||
any => {
|
||||
fnext html;
|
||||
@ -152,12 +150,12 @@ func (lex *Lexer) Lex(lval Lval) int {
|
||||
fbreak;
|
||||
};
|
||||
'<?' => {
|
||||
lex.addFreeFloating(freefloating.TokenType, lex.ts, lex.te)
|
||||
lex.addToken(T_OPEN_TAG, lex.ts, lex.te)
|
||||
fnext php;
|
||||
};
|
||||
'<?php'i ( [ \t] | newline ) => {
|
||||
lex.ungetCnt(lex.te - lex.ts - 5)
|
||||
lex.addFreeFloating(freefloating.TokenType, lex.ts, lex.ts+5)
|
||||
lex.addToken(T_OPEN_TAG, lex.ts, lex.ts+5)
|
||||
fnext php;
|
||||
};
|
||||
'<?='i => {
|
||||
@ -169,7 +167,7 @@ func (lex *Lexer) Lex(lval Lval) int {
|
||||
*|;
|
||||
|
||||
php := |*
|
||||
whitespace_line* => {lex.addFreeFloating(freefloating.WhiteSpaceType, lex.ts, lex.te)};
|
||||
whitespace_line* => {lex.addToken(T_WHITESPACE, lex.ts, lex.te)};
|
||||
'?>' newline? => {lex.setTokenPosition(token); tok = TokenID(int(';')); fnext html; fbreak;};
|
||||
';' whitespace_line* '?>' newline? => {lex.setTokenPosition(token); tok = TokenID(int(';')); fnext html; fbreak;};
|
||||
|
||||
@ -329,17 +327,19 @@ func (lex *Lexer) Lex(lval Lval) int {
|
||||
|
||||
('#' | '//') any_line* when is_not_comment_end => {
|
||||
lex.ungetStr("?>")
|
||||
lex.addFreeFloating(freefloating.CommentType, lex.ts, lex.te)
|
||||
lex.addToken(T_COMMENT, lex.ts, lex.te)
|
||||
};
|
||||
'/*' any_line* :>> '*/' {
|
||||
isDocComment := false;
|
||||
if lex.te - lex.ts > 4 && string(lex.data[lex.ts:lex.ts+3]) == "/**" {
|
||||
isDocComment = true;
|
||||
}
|
||||
lex.addFreeFloating(freefloating.CommentType, lex.ts, lex.te)
|
||||
|
||||
if isDocComment {
|
||||
lex.PhpDocComment = string(lex.data[lex.ts:lex.te])
|
||||
lex.addToken(T_DOC_COMMENT, lex.ts, lex.te)
|
||||
} else {
|
||||
lex.addToken(T_COMMENT, lex.ts, lex.te)
|
||||
}
|
||||
};
|
||||
|
||||
@ -388,7 +388,7 @@ func (lex *Lexer) Lex(lval Lval) int {
|
||||
*|;
|
||||
|
||||
property := |*
|
||||
whitespace_line* => {lex.addFreeFloating(freefloating.WhiteSpaceType, lex.ts, lex.te)};
|
||||
whitespace_line* => {lex.addToken(T_WHITESPACE, lex.ts, lex.te)};
|
||||
"->" => {lex.setTokenPosition(token); tok = T_OBJECT_OPERATOR; fbreak;};
|
||||
varname => {lex.setTokenPosition(token); tok = T_STRING; fnext php; fbreak;};
|
||||
any => {lex.ungetCnt(1); fgoto php;};
|
||||
@ -484,32 +484,32 @@ func (lex *Lexer) Lex(lval Lval) int {
|
||||
*|;
|
||||
|
||||
halt_compiller_open_parenthesis := |*
|
||||
whitespace_line* => {lex.addFreeFloating(freefloating.WhiteSpaceType, lex.ts, lex.te)};
|
||||
whitespace_line* => {lex.addToken(T_WHITESPACE, lex.ts, lex.te)};
|
||||
"(" => {lex.setTokenPosition(token); tok = TokenID(int('(')); fnext halt_compiller_close_parenthesis; fbreak;};
|
||||
any => {lex.ungetCnt(1); fnext php;};
|
||||
*|;
|
||||
|
||||
halt_compiller_close_parenthesis := |*
|
||||
whitespace_line* => {lex.addFreeFloating(freefloating.WhiteSpaceType, lex.ts, lex.te)};
|
||||
whitespace_line* => {lex.addToken(T_WHITESPACE, lex.ts, lex.te)};
|
||||
")" => {lex.setTokenPosition(token); tok = TokenID(int(')')); fnext halt_compiller_close_semicolon; fbreak;};
|
||||
any => {lex.ungetCnt(1); fnext php;};
|
||||
*|;
|
||||
|
||||
halt_compiller_close_semicolon := |*
|
||||
whitespace_line* => {lex.addFreeFloating(freefloating.WhiteSpaceType, lex.ts, lex.te)};
|
||||
whitespace_line* => {lex.addToken(T_WHITESPACE, lex.ts, lex.te)};
|
||||
";" => {lex.setTokenPosition(token); tok = TokenID(int(';')); fnext halt_compiller_end; fbreak;};
|
||||
any => {lex.ungetCnt(1); fnext php;};
|
||||
*|;
|
||||
|
||||
halt_compiller_end := |*
|
||||
any_line* => { lex.addFreeFloating(freefloating.TokenType, lex.ts, lex.te); };
|
||||
any_line* => { lex.addToken(T_HALT_COMPILER, lex.ts, lex.te); };
|
||||
*|;
|
||||
|
||||
write exec;
|
||||
}%%
|
||||
|
||||
token.FreeFloating = lex.FreeFloating
|
||||
token.Value = string(lex.data[lex.ts:lex.te])
|
||||
token.Tokens = lex.Tokens
|
||||
token.Value = lex.data[lex.ts:lex.te]
|
||||
|
||||
lval.Token(token)
|
||||
|
@ -3,8 +3,7 @@ package scanner
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
"github.com/z7zmey/php-parser/position"
|
||||
"github.com/z7zmey/php-parser/pkg/token"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
@ -361,7 +360,7 @@ func TestTokens(t *testing.T) {
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -390,15 +389,15 @@ func TestShebang(t *testing.T) {
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
token := lexer.Lex(lv)
|
||||
assert.Equal(t, token, int(T_DNUMBER))
|
||||
|
||||
for _, tt := range lv.Tkn.FreeFloating {
|
||||
actual = append(actual, tt.Value)
|
||||
for _, tt := range lv.Tkn.Tokens {
|
||||
actual = append(actual, string(tt.Value))
|
||||
}
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
@ -411,12 +410,12 @@ func TestShebangHtml(t *testing.T) {
|
||||
`
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
token := lexer.Lex(lv)
|
||||
assert.Equal(t, token, int(T_INLINE_HTML))
|
||||
assert.Equal(t, lv.Tkn.FreeFloating[0].Value, "#!/usr/bin/env php\n")
|
||||
assert.Equal(t, string(lv.Tkn.Tokens[0].Value), "#!/usr/bin/env php\n")
|
||||
|
||||
token = lexer.Lex(lv)
|
||||
assert.Equal(t, token, int(T_DNUMBER))
|
||||
@ -462,7 +461,7 @@ func TestNumberTokens(t *testing.T) {
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -520,7 +519,7 @@ func TestConstantStrings(t *testing.T) {
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -656,7 +655,7 @@ func TestTeplateStringTokens(t *testing.T) {
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -742,7 +741,7 @@ func TestBackquoteStringTokens(t *testing.T) {
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -837,7 +836,7 @@ CAT;
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -911,7 +910,7 @@ CAT
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -951,7 +950,7 @@ CAT;
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -983,7 +982,7 @@ func TestHereDocTokens73(t *testing.T) {
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -1015,7 +1014,7 @@ CAT;`
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.PHPVersion = "7.2"
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -1048,7 +1047,7 @@ func TestInlineHtmlNopTokens(t *testing.T) {
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
actual := []string{}
|
||||
|
||||
@ -1094,7 +1093,7 @@ func TestStringTokensAfterVariable(t *testing.T) {
|
||||
break
|
||||
}
|
||||
|
||||
actualTokens = append(actualTokens, lv.Tkn.Value)
|
||||
actualTokens = append(actualTokens, string(lv.Tkn.Value))
|
||||
actual = append(actual, TokenID(token).String())
|
||||
}
|
||||
|
||||
@ -1128,7 +1127,7 @@ func TestSlashAfterVariable(t *testing.T) {
|
||||
break
|
||||
}
|
||||
|
||||
actualTokens = append(actualTokens, lv.Tkn.Value)
|
||||
actualTokens = append(actualTokens, string(lv.Tkn.Value))
|
||||
actual = append(actual, TokenID(token).String())
|
||||
}
|
||||
|
||||
@ -1139,31 +1138,29 @@ func TestSlashAfterVariable(t *testing.T) {
|
||||
func TestCommentEnd(t *testing.T) {
|
||||
src := `<?php //test`
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
|
||||
{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 1, 5, 6),
|
||||
},
|
||||
{
|
||||
Value: "//test",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: position.NewPosition(1, 1, 6, 12),
|
||||
ID: token.T_COMMENT,
|
||||
Value: []byte("//test"),
|
||||
},
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
|
||||
actual := lexer.FreeFloating
|
||||
actual := lexer.Tokens
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@ -1171,31 +1168,29 @@ func TestCommentEnd(t *testing.T) {
|
||||
func TestCommentNewLine(t *testing.T) {
|
||||
src := "<?php //test\n$a"
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
|
||||
{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 1, 5, 6),
|
||||
},
|
||||
{
|
||||
Value: "//test\n",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: position.NewPosition(1, 1, 6, 13),
|
||||
ID: token.T_COMMENT,
|
||||
Value: []byte("//test\n"),
|
||||
},
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
|
||||
actual := lv.Tkn.FreeFloating
|
||||
actual := lv.Tkn.Tokens
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@ -1203,31 +1198,29 @@ func TestCommentNewLine(t *testing.T) {
|
||||
func TestCommentNewLine1(t *testing.T) {
|
||||
src := "<?php //test\r$a"
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
|
||||
{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 1, 5, 6),
|
||||
},
|
||||
{
|
||||
Value: "//test\r",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: position.NewPosition(1, 1, 6, 13),
|
||||
ID: token.T_COMMENT,
|
||||
Value: []byte("//test\r"),
|
||||
},
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
|
||||
actual := lv.Tkn.FreeFloating
|
||||
actual := lv.Tkn.Tokens
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@ -1235,31 +1228,29 @@ func TestCommentNewLine1(t *testing.T) {
|
||||
func TestCommentNewLine2(t *testing.T) {
|
||||
src := "<?php #test\r\n$a"
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
|
||||
{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 1, 5, 6),
|
||||
},
|
||||
{
|
||||
Value: "#test\r\n",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: position.NewPosition(1, 1, 6, 13),
|
||||
ID: token.T_COMMENT,
|
||||
Value: []byte("#test\r\n"),
|
||||
},
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
|
||||
actual := lv.Tkn.FreeFloating
|
||||
actual := lv.Tkn.Tokens
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@ -1268,31 +1259,29 @@ func TestCommentWithPhpEndTag(t *testing.T) {
|
||||
src := `<?php
|
||||
//test?> test`
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
|
||||
{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte("\n\t"),
|
||||
},
|
||||
{
|
||||
Value: "\n\t",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 2, 5, 7),
|
||||
},
|
||||
{
|
||||
Value: "//test",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: position.NewPosition(2, 2, 7, 13),
|
||||
ID: token.T_COMMENT,
|
||||
Value: []byte("//test"),
|
||||
},
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
|
||||
actual := lv.Tkn.FreeFloating
|
||||
actual := lv.Tkn.Tokens
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@ -1301,31 +1290,29 @@ func TestInlineComment(t *testing.T) {
|
||||
src := `<?php
|
||||
/*test*/`
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
|
||||
{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte("\n\t"),
|
||||
},
|
||||
{
|
||||
Value: "\n\t",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 2, 5, 7),
|
||||
},
|
||||
{
|
||||
Value: "/*test*/",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: position.NewPosition(2, 2, 7, 15),
|
||||
ID: token.T_COMMENT,
|
||||
Value: []byte("/*test*/"),
|
||||
},
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
|
||||
actual := lv.Tkn.FreeFloating
|
||||
actual := lv.Tkn.Tokens
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@ -1334,31 +1321,29 @@ func TestInlineComment2(t *testing.T) {
|
||||
src := `<?php
|
||||
/*/*/`
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
|
||||
{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte("\n\t"),
|
||||
},
|
||||
{
|
||||
Value: "\n\t",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 2, 5, 7),
|
||||
},
|
||||
{
|
||||
Value: "/*/*/",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: position.NewPosition(2, 2, 7, 12),
|
||||
ID: token.T_COMMENT,
|
||||
Value: []byte("/*/*/"),
|
||||
},
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
|
||||
actual := lexer.FreeFloating
|
||||
actual := lexer.Tokens
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@ -1367,36 +1352,33 @@ func TestEmptyInlineComment(t *testing.T) {
|
||||
src := `<?php
|
||||
/**/ `
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
|
||||
{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte("\n\t"),
|
||||
},
|
||||
{
|
||||
Value: "\n\t",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 2, 5, 7),
|
||||
ID: token.T_COMMENT,
|
||||
Value: []byte("/**/"),
|
||||
},
|
||||
{
|
||||
Value: "/**/",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: position.NewPosition(2, 2, 7, 11),
|
||||
},
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(2, 2, 11, 12),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
|
||||
actual := lexer.FreeFloating
|
||||
actual := lexer.Tokens
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@ -1405,31 +1387,29 @@ func TestEmptyInlineComment2(t *testing.T) {
|
||||
src := `<?php
|
||||
/***/`
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
|
||||
{
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte("\n\t"),
|
||||
},
|
||||
{
|
||||
Value: "\n\t",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 2, 5, 7),
|
||||
},
|
||||
{
|
||||
Value: "/***/",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: position.NewPosition(2, 2, 7, 12),
|
||||
ID: token.T_DOC_COMMENT,
|
||||
Value: []byte("/***/"),
|
||||
},
|
||||
}
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
|
||||
actual := lv.Tkn.FreeFloating
|
||||
actual := lv.Tkn.Tokens
|
||||
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@ -1439,89 +1419,81 @@ func TestMethodCallTokens(t *testing.T) {
|
||||
$a -> bar ( '' ) ;`
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
{
|
||||
Value: "\n\t",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 2, 5, 7),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte("\n\t"),
|
||||
},
|
||||
}
|
||||
lexer.Lex(lv)
|
||||
actual := lv.Tkn.FreeFloating
|
||||
actual := lv.Tkn.Tokens
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = []freefloating.String{
|
||||
expected = []token.Token{
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(2, 2, 9, 10),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
}
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.FreeFloating
|
||||
actual = lv.Tkn.Tokens
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = []freefloating.String{
|
||||
expected = []token.Token{
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(2, 2, 12, 13),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
}
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.FreeFloating
|
||||
actual = lv.Tkn.Tokens
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = []freefloating.String{
|
||||
expected = []token.Token{
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(2, 2, 16, 17),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
}
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.FreeFloating
|
||||
actual = lv.Tkn.Tokens
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = []freefloating.String{
|
||||
expected = []token.Token{
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(2, 2, 18, 19),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
}
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.FreeFloating
|
||||
actual = lv.Tkn.Tokens
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = []freefloating.String{
|
||||
expected = []token.Token{
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(2, 2, 21, 22),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
}
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.FreeFloating
|
||||
actual = lv.Tkn.Tokens
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = []freefloating.String{
|
||||
expected = []token.Token{
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(2, 2, 23, 24),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
}
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.FreeFloating
|
||||
actual = lv.Tkn.Tokens
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
@ -1530,34 +1502,31 @@ func TestYieldFromTokens(t *testing.T) {
|
||||
yield from $a`
|
||||
|
||||
lexer := NewLexer([]byte(src))
|
||||
lexer.WithFreeFloating = true
|
||||
lexer.WithTokens = true
|
||||
lv := &lval{}
|
||||
|
||||
expected := []freefloating.String{
|
||||
expected := []token.Token{
|
||||
{
|
||||
Value: "<?php",
|
||||
StringType: freefloating.TokenType,
|
||||
Position: position.NewPosition(1, 1, 0, 5),
|
||||
ID: token.T_OPEN_TAG,
|
||||
Value: []byte("<?php"),
|
||||
},
|
||||
{
|
||||
Value: "\n\t",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(1, 2, 5, 7),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte("\n\t"),
|
||||
},
|
||||
}
|
||||
lexer.Lex(lv)
|
||||
actual := lv.Tkn.FreeFloating
|
||||
actual := lv.Tkn.Tokens
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = []freefloating.String{
|
||||
expected = []token.Token{
|
||||
{
|
||||
Value: " ",
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Position: position.NewPosition(2, 2, 17, 18),
|
||||
ID: token.T_WHITESPACE,
|
||||
Value: []byte(" "),
|
||||
},
|
||||
}
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.FreeFloating
|
||||
actual = lv.Tkn.Tokens
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
@ -1568,10 +1537,10 @@ func TestVarNameByteChars(t *testing.T) {
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
assert.Equal(t, "$\x80", lv.Tkn.Value)
|
||||
assert.Equal(t, "$\x80", string(lv.Tkn.Value))
|
||||
|
||||
lexer.Lex(lv)
|
||||
assert.Equal(t, "$\xff", lv.Tkn.Value)
|
||||
assert.Equal(t, "$\xff", string(lv.Tkn.Value))
|
||||
}
|
||||
|
||||
func TestStringVarNameByteChars(t *testing.T) {
|
||||
@ -1581,19 +1550,19 @@ func TestStringVarNameByteChars(t *testing.T) {
|
||||
lv := &lval{}
|
||||
|
||||
lexer.Lex(lv)
|
||||
assert.Equal(t, "\"", lv.Tkn.Value)
|
||||
assert.Equal(t, "\"", string(lv.Tkn.Value))
|
||||
|
||||
lexer.Lex(lv)
|
||||
assert.Equal(t, "$\x80", lv.Tkn.Value)
|
||||
assert.Equal(t, "$\x80", string(lv.Tkn.Value))
|
||||
|
||||
lexer.Lex(lv)
|
||||
assert.Equal(t, " ", lv.Tkn.Value)
|
||||
assert.Equal(t, " ", string(lv.Tkn.Value))
|
||||
|
||||
lexer.Lex(lv)
|
||||
assert.Equal(t, "$\xff", lv.Tkn.Value)
|
||||
assert.Equal(t, "$\xff", string(lv.Tkn.Value))
|
||||
|
||||
lexer.Lex(lv)
|
||||
assert.Equal(t, "\"", lv.Tkn.Value)
|
||||
assert.Equal(t, "\"", string(lv.Tkn.Value))
|
||||
}
|
||||
|
||||
func TestIgnoreControllCharacters(t *testing.T) {
|
||||
@ -1604,12 +1573,12 @@ func TestIgnoreControllCharacters(t *testing.T) {
|
||||
|
||||
expected := "echo"
|
||||
lexer.Lex(lv)
|
||||
actual := lv.Tkn.Value
|
||||
actual := string(lv.Tkn.Value)
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = "$b"
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.Value
|
||||
actual = string(lv.Tkn.Value)
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
@ -1621,26 +1590,26 @@ func TestIgnoreControllCharactersAtStringVarOffset(t *testing.T) {
|
||||
|
||||
expected := "\""
|
||||
lexer.Lex(lv)
|
||||
actual := lv.Tkn.Value
|
||||
actual := string(lv.Tkn.Value)
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = "$a"
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.Value
|
||||
actual = string(lv.Tkn.Value)
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = "["
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.Value
|
||||
actual = string(lv.Tkn.Value)
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = "test"
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.Value
|
||||
actual = string(lv.Tkn.Value)
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
|
||||
expected = "]"
|
||||
lexer.Lex(lv)
|
||||
actual = lv.Tkn.Value
|
||||
actual = string(lv.Tkn.Value)
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
15
internal/scanner/token.go
Normal file
15
internal/scanner/token.go
Normal file
@ -0,0 +1,15 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"github.com/z7zmey/php-parser/pkg/token"
|
||||
)
|
||||
|
||||
// Token value returned by lexer
|
||||
type Token struct {
|
||||
Value []byte
|
||||
Tokens []token.Token
|
||||
StartLine int
|
||||
EndLine int
|
||||
StartPos int
|
||||
EndPos int
|
||||
}
|
@ -4,7 +4,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/z7zmey/php-parser/scanner"
|
||||
"github.com/z7zmey/php-parser/internal/scanner"
|
||||
)
|
||||
|
||||
func TestTokenPoolGetNew(t *testing.T) {
|
||||
@ -21,7 +21,7 @@ func TestTokenPoolGetFromPool(t *testing.T) {
|
||||
tp := new(scanner.TokenPool)
|
||||
|
||||
expectedToken := &scanner.Token{
|
||||
Value: "test",
|
||||
Value: []byte("test"),
|
||||
}
|
||||
|
||||
tp.Put(expectedToken)
|
225
php7/parser.go
225
php7/parser.go
@ -1,225 +0,0 @@
|
||||
package php7
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/z7zmey/php-parser/errors"
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/position"
|
||||
"github.com/z7zmey/php-parser/positionbuilder"
|
||||
"github.com/z7zmey/php-parser/scanner"
|
||||
)
|
||||
|
||||
func (lval *yySymType) Token(t *scanner.Token) {
|
||||
lval.token = t
|
||||
}
|
||||
|
||||
// Parser structure
|
||||
type Parser struct {
|
||||
Lexer scanner.Scanner
|
||||
currentToken *scanner.Token
|
||||
positionBuilder *positionbuilder.PositionBuilder
|
||||
rootNode node.Node
|
||||
}
|
||||
|
||||
// NewParser creates and returns new Parser
|
||||
func NewParser(src []byte, v string) *Parser {
|
||||
lexer := scanner.NewLexer(src)
|
||||
lexer.PHPVersion = v
|
||||
|
||||
return &Parser{
|
||||
lexer,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Parser) Lex(lval *yySymType) int {
|
||||
t := l.Lexer.Lex(lval)
|
||||
l.currentToken = lval.token
|
||||
return t
|
||||
}
|
||||
|
||||
func (l *Parser) Error(msg string) {
|
||||
pos := &position.Position{
|
||||
StartLine: l.currentToken.StartLine,
|
||||
EndLine: l.currentToken.EndLine,
|
||||
StartPos: l.currentToken.StartPos,
|
||||
EndPos: l.currentToken.EndPos,
|
||||
}
|
||||
|
||||
l.Lexer.AddError(errors.NewError(msg, pos))
|
||||
}
|
||||
|
||||
func (l *Parser) WithFreeFloating() {
|
||||
l.Lexer.SetWithFreeFloating(true)
|
||||
}
|
||||
|
||||
// Parse the php7 Parser entrypoint
|
||||
func (l *Parser) Parse() int {
|
||||
// init
|
||||
l.Lexer.SetErrors(nil)
|
||||
l.rootNode = nil
|
||||
l.positionBuilder = &positionbuilder.PositionBuilder{}
|
||||
|
||||
// parse
|
||||
|
||||
return yyParse(l)
|
||||
}
|
||||
|
||||
// GetRootNode returns root node
|
||||
func (l *Parser) GetRootNode() node.Node {
|
||||
return l.rootNode
|
||||
}
|
||||
|
||||
// GetErrors returns errors list
|
||||
func (l *Parser) GetErrors() []*errors.Error {
|
||||
return l.Lexer.GetErrors()
|
||||
}
|
||||
|
||||
// helpers
|
||||
|
||||
func lastNode(nn []node.Node) node.Node {
|
||||
if len(nn) == 0 {
|
||||
return nil
|
||||
}
|
||||
return nn[len(nn)-1]
|
||||
}
|
||||
|
||||
func firstNode(nn []node.Node) node.Node {
|
||||
return nn[0]
|
||||
}
|
||||
|
||||
func isDollar(r rune) bool {
|
||||
return r == '$'
|
||||
}
|
||||
|
||||
func (l *Parser) MoveFreeFloating(src node.Node, dst node.Node) {
|
||||
if l.Lexer.GetWithFreeFloating() == false {
|
||||
return
|
||||
}
|
||||
|
||||
if src.GetFreeFloating() == nil {
|
||||
return
|
||||
}
|
||||
|
||||
l.setFreeFloating(dst, freefloating.Start, (*src.GetFreeFloating())[freefloating.Start])
|
||||
delete((*src.GetFreeFloating()), freefloating.Start)
|
||||
}
|
||||
|
||||
func (l *Parser) setFreeFloating(dst node.Node, p freefloating.Position, strings []freefloating.String) {
|
||||
if l.Lexer.GetWithFreeFloating() == false {
|
||||
return
|
||||
}
|
||||
|
||||
if len(strings) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
dstCollection := dst.GetFreeFloating()
|
||||
if *dstCollection == nil {
|
||||
*dstCollection = make(freefloating.Collection)
|
||||
}
|
||||
|
||||
(*dstCollection)[p] = strings
|
||||
}
|
||||
|
||||
func (l *Parser) GetFreeFloatingToken(t *scanner.Token) []freefloating.String {
|
||||
if l.Lexer.GetWithFreeFloating() == false {
|
||||
return []freefloating.String{}
|
||||
}
|
||||
|
||||
return t.GetFreeFloatingToken()
|
||||
}
|
||||
|
||||
func (l *Parser) addDollarToken(v node.Node) {
|
||||
if l.Lexer.GetWithFreeFloating() == false {
|
||||
return
|
||||
}
|
||||
|
||||
l.setFreeFloating(v, freefloating.Dollar, []freefloating.String{
|
||||
{
|
||||
StringType: freefloating.TokenType,
|
||||
Value: "$",
|
||||
Position: &position.Position{
|
||||
StartLine: v.GetPosition().StartLine,
|
||||
EndLine: v.GetPosition().StartLine,
|
||||
StartPos: v.GetPosition().StartPos,
|
||||
EndPos: v.GetPosition().StartPos + 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (l *Parser) splitSemiColonAndPhpCloseTag(htmlNode node.Node, prevNode node.Node) {
|
||||
if l.Lexer.GetWithFreeFloating() == false {
|
||||
return
|
||||
}
|
||||
|
||||
semiColon := (*prevNode.GetFreeFloating())[freefloating.SemiColon]
|
||||
delete((*prevNode.GetFreeFloating()), freefloating.SemiColon)
|
||||
if len(semiColon) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
p := semiColon[0].Position
|
||||
if semiColon[0].Value[0] == ';' {
|
||||
l.setFreeFloating(prevNode, freefloating.SemiColon, []freefloating.String{
|
||||
{
|
||||
StringType: freefloating.TokenType,
|
||||
Value: ";",
|
||||
Position: &position.Position{
|
||||
StartLine: p.StartLine,
|
||||
EndLine: p.StartLine,
|
||||
StartPos: p.StartPos,
|
||||
EndPos: p.StartPos + 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
vlen := len(semiColon[0].Value)
|
||||
tlen := 2
|
||||
if strings.HasSuffix(semiColon[0].Value, "?>\n") {
|
||||
tlen = 3
|
||||
}
|
||||
|
||||
phpCloseTag := []freefloating.String{}
|
||||
if vlen-tlen > 1 {
|
||||
phpCloseTag = append(phpCloseTag, freefloating.String{
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Value: semiColon[0].Value[1 : vlen-tlen],
|
||||
Position: &position.Position{
|
||||
StartLine: p.StartLine,
|
||||
EndLine: p.EndLine,
|
||||
StartPos: p.StartPos + 1,
|
||||
EndPos: p.EndPos - tlen,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
phpCloseTag = append(phpCloseTag, freefloating.String{
|
||||
StringType: freefloating.WhiteSpaceType,
|
||||
Value: semiColon[0].Value[vlen-tlen:],
|
||||
Position: &position.Position{
|
||||
StartLine: p.EndLine,
|
||||
EndLine: p.EndLine,
|
||||
StartPos: p.EndPos - tlen,
|
||||
EndPos: p.EndPos,
|
||||
},
|
||||
})
|
||||
|
||||
l.setFreeFloating(htmlNode, freefloating.Start, append(phpCloseTag, (*htmlNode.GetFreeFloating())[freefloating.Start]...))
|
||||
}
|
||||
|
||||
func (p *Parser) returnTokenToPool(yyDollar []yySymType, yyVAL *yySymType) {
|
||||
for i := 1; i < len(yyDollar); i++ {
|
||||
if yyDollar[i].token != nil {
|
||||
p.Lexer.ReturnTokenToPool(yyDollar[i].token)
|
||||
}
|
||||
yyDollar[i].token = nil
|
||||
}
|
||||
yyVAL.token = nil
|
||||
}
|
5666
php7/php7.y
5666
php7/php7.y
File diff suppressed because it is too large
Load Diff
16450
php7/php7_test.go
16450
php7/php7_test.go
File diff suppressed because it is too large
Load Diff
@ -189,4 +189,9 @@ type NodeVisitor interface {
|
||||
ScalarLnumber(n *ScalarLnumber)
|
||||
ScalarMagicConstant(n *ScalarMagicConstant)
|
||||
ScalarString(n *ScalarString)
|
||||
|
||||
NameName(n *NameName)
|
||||
NameFullyQualified(n *NameFullyQualified)
|
||||
NameRelative(n *NameRelative)
|
||||
NameNamePart(n *NameNamePart)
|
||||
}
|
||||
|
@ -53,7 +53,6 @@ type testVisitor struct {
|
||||
depth int
|
||||
}
|
||||
|
||||
|
||||
func (v *testVisitor) Enter(key string, _ bool) {
|
||||
v.depth++
|
||||
fmt.Fprint(os.Stdout, "=>", strings.Repeat(" ", v.depth), key, ":\n")
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
type Node struct {
|
||||
StartTokens []token.Token
|
||||
EndTokens []token.Token
|
||||
Tokens token.Collection
|
||||
Position *position.Position
|
||||
}
|
||||
|
||||
@ -52,7 +53,7 @@ func (n *Parameter) Accept(v NodeVisitor) {
|
||||
// Identifier node
|
||||
type Identifier struct {
|
||||
Node
|
||||
Value string
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (n *Identifier) Accept(v NodeVisitor) {
|
||||
@ -84,7 +85,7 @@ func (n *Argument) Accept(v NodeVisitor) {
|
||||
// ScalarDnumber node
|
||||
type ScalarDnumber struct {
|
||||
Node
|
||||
Value string
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (n *ScalarDnumber) Accept(v NodeVisitor) {
|
||||
@ -104,7 +105,7 @@ func (n *ScalarEncapsed) Accept(v NodeVisitor) {
|
||||
// ScalarEncapsedStringPart node
|
||||
type ScalarEncapsedStringPart struct {
|
||||
Node
|
||||
Value string
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (n *ScalarEncapsedStringPart) Accept(v NodeVisitor) {
|
||||
@ -114,7 +115,7 @@ func (n *ScalarEncapsedStringPart) Accept(v NodeVisitor) {
|
||||
// ScalarHeredoc node
|
||||
type ScalarHeredoc struct {
|
||||
Node
|
||||
Label string
|
||||
Label []byte
|
||||
Parts []Vertex
|
||||
}
|
||||
|
||||
@ -125,7 +126,7 @@ func (n *ScalarHeredoc) Accept(v NodeVisitor) {
|
||||
// ScalarLnumber node
|
||||
type ScalarLnumber struct {
|
||||
Node
|
||||
Value string
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (n *ScalarLnumber) Accept(v NodeVisitor) {
|
||||
@ -135,7 +136,7 @@ func (n *ScalarLnumber) Accept(v NodeVisitor) {
|
||||
// ScalarMagicConstant node
|
||||
type ScalarMagicConstant struct {
|
||||
Node
|
||||
Value string
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (n *ScalarMagicConstant) Accept(v NodeVisitor) {
|
||||
@ -145,7 +146,7 @@ func (n *ScalarMagicConstant) Accept(v NodeVisitor) {
|
||||
// ScalarString node
|
||||
type ScalarString struct {
|
||||
Node
|
||||
Value string
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (n *ScalarString) Accept(v NodeVisitor) {
|
||||
@ -550,7 +551,7 @@ func (n *StmtIf) Accept(v NodeVisitor) {
|
||||
// StmtInlineHtml node
|
||||
type StmtInlineHtml struct {
|
||||
Node
|
||||
Value string
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (n *StmtInlineHtml) Accept(v NodeVisitor) {
|
||||
@ -1803,3 +1804,39 @@ type ExprBinarySpaceship struct {
|
||||
func (n *ExprBinarySpaceship) Accept(v NodeVisitor) {
|
||||
v.ExprBinarySpaceship(n)
|
||||
}
|
||||
|
||||
type NameName struct {
|
||||
Node
|
||||
Parts []Vertex
|
||||
}
|
||||
|
||||
func (n *NameName) Accept(v NodeVisitor) {
|
||||
v.NameName(n)
|
||||
}
|
||||
|
||||
type NameFullyQualified struct {
|
||||
Node
|
||||
Parts []Vertex
|
||||
}
|
||||
|
||||
func (n *NameFullyQualified) Accept(v NodeVisitor) {
|
||||
v.NameFullyQualified(n)
|
||||
}
|
||||
|
||||
type NameRelative struct {
|
||||
Node
|
||||
Parts []Vertex
|
||||
}
|
||||
|
||||
func (n *NameRelative) Accept(v NodeVisitor) {
|
||||
v.NameRelative(n)
|
||||
}
|
||||
|
||||
type NameNamePart struct {
|
||||
Node
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (n *NameNamePart) Accept(v NodeVisitor) {
|
||||
v.NameNamePart(n)
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ func ExampleDump() {
|
||||
&ast.Identifier{},
|
||||
&ast.Parameter{
|
||||
Variadic: true,
|
||||
Var: &ast.ExprVariable{
|
||||
},
|
||||
Var: &ast.ExprVariable{},
|
||||
},
|
||||
&ast.StmtInlineHtml{
|
||||
Value: "foo",
|
||||
|
@ -3,7 +3,7 @@ package errors
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/z7zmey/php-parser/position"
|
||||
"github.com/z7zmey/php-parser/pkg/position"
|
||||
)
|
||||
|
||||
// Error parsing error
|
@ -1,19 +1,19 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"github.com/z7zmey/php-parser/errors"
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/php5"
|
||||
"github.com/z7zmey/php-parser/php7"
|
||||
"github.com/z7zmey/php-parser/version"
|
||||
"github.com/z7zmey/php-parser/internal/php5"
|
||||
"github.com/z7zmey/php-parser/internal/php7"
|
||||
"github.com/z7zmey/php-parser/internal/version"
|
||||
"github.com/z7zmey/php-parser/pkg/ast"
|
||||
"github.com/z7zmey/php-parser/pkg/errors"
|
||||
)
|
||||
|
||||
// Parser interface
|
||||
type Parser interface {
|
||||
Parse() int
|
||||
GetRootNode() node.Node
|
||||
GetRootNode() ast.Vertex
|
||||
GetErrors() []*errors.Error
|
||||
WithFreeFloating()
|
||||
WithTokens()
|
||||
}
|
||||
|
||||
func NewParser(src []byte, v string) (Parser, error) {
|
@ -1,17 +1,9 @@
|
||||
package freefloating
|
||||
|
||||
import "github.com/z7zmey/php-parser/position"
|
||||
|
||||
type StringType int
|
||||
|
||||
const (
|
||||
WhiteSpaceType StringType = iota
|
||||
CommentType
|
||||
TokenType
|
||||
)
|
||||
package token
|
||||
|
||||
type Position int
|
||||
|
||||
type Collection map[Position][]Token
|
||||
|
||||
//go:generate stringer -type=Position -output ./position_string.go
|
||||
const (
|
||||
Start Position = iota
|
||||
@ -94,20 +86,3 @@ const (
|
||||
OpenParenthesisToken
|
||||
CloseParenthesisToken
|
||||
)
|
||||
|
||||
type String struct {
|
||||
StringType StringType
|
||||
Value string
|
||||
Position *position.Position
|
||||
}
|
||||
|
||||
type Collection map[Position][]String
|
||||
|
||||
func (c Collection) IsEmpty() bool {
|
||||
for _, v := range c {
|
||||
if len(v) > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// Code generated by "stringer -type=Position -output ./position_string.go"; DO NOT EDIT.
|
||||
|
||||
package freefloating
|
||||
package token
|
||||
|
||||
import "strconv"
|
||||
|
@ -1,9 +1,9 @@
|
||||
package token
|
||||
|
||||
type TokenID int
|
||||
type ID int
|
||||
|
||||
const (
|
||||
T_INCLUDE TokenID = iota + 57346
|
||||
T_INCLUDE ID = iota + 57346
|
||||
T_INCLUDE_ONCE
|
||||
T_EXIT
|
||||
T_IF
|
||||
@ -144,6 +144,6 @@ const (
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
ID TokenID
|
||||
ID ID
|
||||
Value []byte
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
package position
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Position represents node position
|
||||
type Position struct {
|
||||
StartLine int
|
||||
EndLine int
|
||||
StartPos int
|
||||
EndPos int
|
||||
}
|
||||
|
||||
// NewPosition Position constructor
|
||||
func NewPosition(StartLine int, EndLine int, StartPos int, EndPos int) *Position {
|
||||
return &Position{
|
||||
StartLine: StartLine,
|
||||
EndLine: EndLine,
|
||||
StartPos: StartPos,
|
||||
EndPos: EndPos,
|
||||
}
|
||||
}
|
||||
|
||||
func (p Position) String() string {
|
||||
return fmt.Sprintf("Pos{Line: %d-%d Pos: %d-%d}", p.StartLine, p.EndLine, p.StartPos, p.EndPos)
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package position_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/z7zmey/php-parser/position"
|
||||
)
|
||||
|
||||
func TestPrintPosition(t *testing.T) {
|
||||
pos := position.NewPosition(1, 1, 2, 5)
|
||||
|
||||
expected := "Pos{Line: 1-1 Pos: 2-5}"
|
||||
|
||||
actual := pos.String()
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("expected and actual are not equal\n")
|
||||
}
|
||||
}
|
@ -1,463 +0,0 @@
|
||||
package positionbuilder_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/position"
|
||||
"github.com/z7zmey/php-parser/positionbuilder"
|
||||
|
||||
"github.com/z7zmey/php-parser/scanner"
|
||||
)
|
||||
|
||||
func TestNewTokenPosition(t *testing.T) {
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
tkn := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
|
||||
pos := builder.NewTokenPosition(tkn)
|
||||
|
||||
if pos.String() != `Pos{Line: 1-1 Pos: 0-3}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTokensPosition(t *testing.T) {
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
token1 := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
token2 := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 4,
|
||||
EndPos: 6,
|
||||
}
|
||||
|
||||
pos := builder.NewTokensPosition(token1, token2)
|
||||
|
||||
if pos.String() != `Pos{Line: 1-2 Pos: 0-6}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewNodePosition(t *testing.T) {
|
||||
n := node.NewIdentifier("test node")
|
||||
n.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodePosition(n)
|
||||
|
||||
if pos.String() != `Pos{Line: 1-1 Pos: 0-3}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTokenNodePosition(t *testing.T) {
|
||||
tkn := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
n := node.NewIdentifier("test node")
|
||||
n.SetPosition(&position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 4,
|
||||
EndPos: 12,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewTokenNodePosition(tkn, n)
|
||||
|
||||
if pos.String() != `Pos{Line: 1-2 Pos: 0-12}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewNodeTokenPosition(t *testing.T) {
|
||||
n := node.NewIdentifier("test node")
|
||||
n.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 9,
|
||||
})
|
||||
|
||||
tkn := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 10,
|
||||
EndPos: 12,
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeTokenPosition(n, tkn)
|
||||
|
||||
if pos.String() != `Pos{Line: 1-2 Pos: 0-12}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewNodeListPosition(t *testing.T) {
|
||||
n1 := node.NewIdentifier("test node")
|
||||
n1.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 9,
|
||||
})
|
||||
|
||||
n2 := node.NewIdentifier("test node")
|
||||
n2.SetPosition(&position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 10,
|
||||
EndPos: 19,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListPosition([]node.Node{n1, n2})
|
||||
|
||||
if pos.String() != `Pos{Line: 1-2 Pos: 0-19}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewNodesPosition(t *testing.T) {
|
||||
n1 := node.NewIdentifier("test node")
|
||||
n1.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 9,
|
||||
})
|
||||
|
||||
n2 := node.NewIdentifier("test node")
|
||||
n2.SetPosition(&position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 10,
|
||||
EndPos: 19,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodesPosition(n1, n2)
|
||||
|
||||
if pos.String() != `Pos{Line: 1-2 Pos: 0-19}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewNodeListTokenPosition(t *testing.T) {
|
||||
n1 := node.NewIdentifier("test node")
|
||||
n1.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 9,
|
||||
})
|
||||
|
||||
n2 := node.NewIdentifier("test node")
|
||||
n2.SetPosition(&position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 10,
|
||||
EndPos: 19,
|
||||
})
|
||||
|
||||
tkn := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 20,
|
||||
EndPos: 22,
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListTokenPosition([]node.Node{n1, n2}, tkn)
|
||||
|
||||
if pos.String() != `Pos{Line: 1-3 Pos: 0-22}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTokenNodeListPosition(t *testing.T) {
|
||||
tkn := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 2,
|
||||
}
|
||||
|
||||
n1 := node.NewIdentifier("test node")
|
||||
n1.SetPosition(&position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 3,
|
||||
EndPos: 10,
|
||||
})
|
||||
|
||||
n2 := node.NewIdentifier("test node")
|
||||
n2.SetPosition(&position.Position{
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 11,
|
||||
EndPos: 20,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewTokenNodeListPosition(tkn, []node.Node{n1, n2})
|
||||
|
||||
if pos.String() != `Pos{Line: 1-3 Pos: 0-20}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewNodeNodeListPosition(t *testing.T) {
|
||||
n1 := node.NewIdentifier("test node")
|
||||
n1.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 8,
|
||||
})
|
||||
|
||||
n2 := node.NewIdentifier("test node")
|
||||
n2.SetPosition(&position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 9,
|
||||
EndPos: 17,
|
||||
})
|
||||
|
||||
n3 := node.NewIdentifier("test node")
|
||||
n3.SetPosition(&position.Position{
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 18,
|
||||
EndPos: 26,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeNodeListPosition(n1, []node.Node{n2, n3})
|
||||
|
||||
if pos.String() != `Pos{Line: 1-3 Pos: 0-26}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewNodeListNodePosition(t *testing.T) {
|
||||
n1 := node.NewIdentifier("test node")
|
||||
n1.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 8,
|
||||
})
|
||||
n2 := node.NewIdentifier("test node")
|
||||
n2.SetPosition(&position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 9,
|
||||
EndPos: 17,
|
||||
})
|
||||
n3 := node.NewIdentifier("test node")
|
||||
n3.SetPosition(&position.Position{
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 18,
|
||||
EndPos: 26,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListNodePosition([]node.Node{n1, n2}, n3)
|
||||
|
||||
if pos.String() != `Pos{Line: 1-3 Pos: 0-26}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOptionalListTokensPosition(t *testing.T) {
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
token1 := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
token2 := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 4,
|
||||
EndPos: 6,
|
||||
}
|
||||
|
||||
pos := builder.NewOptionalListTokensPosition(nil, token1, token2)
|
||||
|
||||
if pos.String() != `Pos{Line: 1-2 Pos: 0-6}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOptionalListTokensPosition2(t *testing.T) {
|
||||
n1 := node.NewIdentifier("test node")
|
||||
n1.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 8,
|
||||
})
|
||||
n2 := node.NewIdentifier("test node")
|
||||
n2.SetPosition(&position.Position{
|
||||
StartLine: 2,
|
||||
EndLine: 2,
|
||||
StartPos: 9,
|
||||
EndPos: 17,
|
||||
})
|
||||
n3 := node.NewIdentifier("test node")
|
||||
n3.SetPosition(&position.Position{
|
||||
StartLine: 3,
|
||||
EndLine: 3,
|
||||
StartPos: 18,
|
||||
EndPos: 26,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
token1 := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 4,
|
||||
EndLine: 4,
|
||||
StartPos: 27,
|
||||
EndPos: 29,
|
||||
}
|
||||
token2 := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 5,
|
||||
EndLine: 5,
|
||||
StartPos: 30,
|
||||
EndPos: 32,
|
||||
}
|
||||
|
||||
pos := builder.NewOptionalListTokensPosition([]node.Node{n2, n3}, token1, token2)
|
||||
|
||||
if pos.String() != `Pos{Line: 2-5 Pos: 9-32}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilNodePos(t *testing.T) {
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodesPosition(nil, nil)
|
||||
|
||||
if pos.String() != `Pos{Line: -1--1 Pos: -1--1}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilNodeListPos(t *testing.T) {
|
||||
n1 := node.NewIdentifier("test node")
|
||||
n1.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 8,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeNodeListPosition(n1, nil)
|
||||
|
||||
if pos.String() != `Pos{Line: 1--1 Pos: 0--1}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilNodeListTokenPos(t *testing.T) {
|
||||
token := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListTokenPosition(nil, token)
|
||||
|
||||
if pos.String() != `Pos{Line: -1-1 Pos: -1-3}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyNodeListPos(t *testing.T) {
|
||||
n1 := node.NewIdentifier("test node")
|
||||
n1.SetPosition(&position.Position{
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 8,
|
||||
})
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeNodeListPosition(n1, []node.Node{})
|
||||
|
||||
if pos.String() != `Pos{Line: 1--1 Pos: 0--1}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyNodeListTokenPos(t *testing.T) {
|
||||
token := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
|
||||
builder := positionbuilder.PositionBuilder{}
|
||||
|
||||
pos := builder.NewNodeListTokenPosition([]node.Node{}, token)
|
||||
|
||||
if pos.String() != `Pos{Line: -1-1 Pos: -1-3}` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
"github.com/z7zmey/php-parser/position"
|
||||
)
|
||||
|
||||
// Token value returned by lexer
|
||||
type Token struct {
|
||||
Value string
|
||||
FreeFloating []freefloating.String
|
||||
StartLine int
|
||||
EndLine int
|
||||
StartPos int
|
||||
EndPos int
|
||||
}
|
||||
|
||||
func (t *Token) String() string {
|
||||
return string(t.Value)
|
||||
}
|
||||
|
||||
func (t *Token) GetFreeFloatingToken() []freefloating.String {
|
||||
return []freefloating.String{
|
||||
{
|
||||
StringType: freefloating.TokenType,
|
||||
Value: t.Value,
|
||||
Position: &position.Position{
|
||||
StartLine: t.StartLine,
|
||||
EndLine: t.EndLine,
|
||||
StartPos: t.StartPos,
|
||||
EndPos: t.EndPos,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package scanner_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
"github.com/z7zmey/php-parser/scanner"
|
||||
)
|
||||
|
||||
func TestToken(t *testing.T) {
|
||||
tkn := &scanner.Token{
|
||||
Value: `foo`,
|
||||
StartLine: 1,
|
||||
EndLine: 1,
|
||||
StartPos: 0,
|
||||
EndPos: 3,
|
||||
}
|
||||
|
||||
c := []freefloating.String{
|
||||
{
|
||||
Value: "test comment",
|
||||
StringType: freefloating.CommentType,
|
||||
Position: nil,
|
||||
},
|
||||
}
|
||||
|
||||
tkn.FreeFloating = c
|
||||
|
||||
if !reflect.DeepEqual(tkn.FreeFloating, c) {
|
||||
t.Errorf("comments are not equal\n")
|
||||
}
|
||||
|
||||
if tkn.String() != `foo` {
|
||||
t.Errorf("token value is not equal\n")
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
// Package visitor contains walker.visitor implementations
|
||||
package visitor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/walker"
|
||||
)
|
||||
|
||||
// Dumper writes ast hierarchy to an io.Writer
|
||||
// Also prints comments and positions attached to nodes
|
||||
type Dumper struct {
|
||||
Writer io.Writer
|
||||
Indent string
|
||||
NsResolver *NamespaceResolver
|
||||
}
|
||||
|
||||
// EnterNode is invoked at every node in hierarchy
|
||||
func (d *Dumper) EnterNode(w walker.Walkable) bool {
|
||||
n := w.(node.Node)
|
||||
|
||||
fmt.Fprintf(d.Writer, "%v[%v]\n", d.Indent, reflect.TypeOf(n))
|
||||
|
||||
if n.GetPosition() != nil {
|
||||
fmt.Fprintf(d.Writer, "%v\"Position\": %s\n", d.Indent+" ", n.GetPosition())
|
||||
}
|
||||
|
||||
if d.NsResolver != nil {
|
||||
if namespacedName, ok := d.NsResolver.ResolvedNames[n]; ok {
|
||||
fmt.Fprintf(d.Writer, "%v\"NamespacedName\": %q\n", d.Indent+" ", namespacedName)
|
||||
}
|
||||
}
|
||||
|
||||
if !n.GetFreeFloating().IsEmpty() {
|
||||
fmt.Fprintf(d.Writer, "%v\"freefloating\":\n", d.Indent+" ")
|
||||
for key, freeFloatingStrings := range *n.GetFreeFloating() {
|
||||
for _, freeFloatingString := range freeFloatingStrings {
|
||||
fmt.Fprintf(d.Writer, "%v%q: %q\n", d.Indent+" ", key.String(), freeFloatingString.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if a := n.Attributes(); len(a) > 0 {
|
||||
for key, attr := range a {
|
||||
switch attr.(type) {
|
||||
case string:
|
||||
fmt.Fprintf(d.Writer, "%v\"%v\": %q\n", d.Indent+" ", key, attr)
|
||||
default:
|
||||
fmt.Fprintf(d.Writer, "%v\"%v\": %v\n", d.Indent+" ", key, attr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// LeaveNode is invoked after node process
|
||||
func (d *Dumper) LeaveNode(n walker.Walkable) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// GetChildrenVisitor is invoked at every node parameter that contains children nodes
|
||||
func (d *Dumper) EnterChildNode(key string, w walker.Walkable) {
|
||||
fmt.Fprintf(d.Writer, "%v%q:\n", d.Indent+" ", key)
|
||||
d.Indent = d.Indent + " "
|
||||
}
|
||||
|
||||
func (d *Dumper) LeaveChildNode(key string, w walker.Walkable) {
|
||||
d.Indent = strings.TrimSuffix(d.Indent, " ")
|
||||
}
|
||||
|
||||
func (d *Dumper) EnterChildList(key string, w walker.Walkable) {
|
||||
fmt.Fprintf(d.Writer, "%v%q:\n", d.Indent+" ", key)
|
||||
d.Indent = d.Indent + " "
|
||||
}
|
||||
|
||||
func (d *Dumper) LeaveChildList(key string, w walker.Walkable) {
|
||||
d.Indent = strings.TrimSuffix(d.Indent, " ")
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
package visitor_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/z7zmey/php-parser/php7"
|
||||
"github.com/z7zmey/php-parser/visitor"
|
||||
)
|
||||
|
||||
func ExampleDumper() {
|
||||
src := `<?php
|
||||
|
||||
namespace Foo {
|
||||
class Bar {
|
||||
public function FunctionName(Type $var = null)
|
||||
{
|
||||
// some comment
|
||||
$var;
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
php7parser := php7.NewParser([]byte(src), "7.4")
|
||||
php7parser.WithFreeFloating()
|
||||
php7parser.Parse()
|
||||
nodes := php7parser.GetRootNode()
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
nodes.Walk(nsResolver)
|
||||
|
||||
dumper := &visitor.Dumper{
|
||||
Writer: os.Stdout,
|
||||
Indent: "| ",
|
||||
NsResolver: nsResolver,
|
||||
}
|
||||
nodes.Walk(dumper)
|
||||
|
||||
// Unordered output:
|
||||
// | [*node.Root]
|
||||
// | "Position": Pos{Line: 3-11 Pos: 9-144}
|
||||
// | "Stmts":
|
||||
// | [*stmt.Namespace]
|
||||
// | "Position": Pos{Line: 3-11 Pos: 9-144}
|
||||
// | "freefloating":
|
||||
// | "Start": "<?php"
|
||||
// | "Start": "\n\n\t\t"
|
||||
// | "Stmts": "\n\t\t"
|
||||
// | "NamespaceName":
|
||||
// | [*name.Name]
|
||||
// | "Position": Pos{Line: 3-3 Pos: 19-22}
|
||||
// | "freefloating":
|
||||
// | "Start": " "
|
||||
// | "End": " "
|
||||
// | "Parts":
|
||||
// | [*name.NamePart]
|
||||
// | "Position": Pos{Line: 3-3 Pos: 19-22}
|
||||
// | "Value": "Foo"
|
||||
// | "Stmts":
|
||||
// | [*stmt.Class]
|
||||
// | "Position": Pos{Line: 4-10 Pos: 28-140}
|
||||
// | "NamespacedName": "Foo\\Bar"
|
||||
// | "freefloating":
|
||||
// | "Start": "\n\t\t\t"
|
||||
// | "Name": " "
|
||||
// | "Stmts": "\n\t\t\t"
|
||||
// | "PhpDocComment": ""
|
||||
// | "ClassName":
|
||||
// | [*node.Identifier]
|
||||
// | "Position": Pos{Line: 4-4 Pos: 34-37}
|
||||
// | "freefloating":
|
||||
// | "Start": " "
|
||||
// | "Value": "Bar"
|
||||
// | "Stmts":
|
||||
// | [*stmt.ClassMethod]
|
||||
// | "Position": Pos{Line: 5-9 Pos: 45-135}
|
||||
// | "freefloating":
|
||||
// | "Start": " \n\t\t\t\t"
|
||||
// | "ModifierList": " "
|
||||
// | "Function": " "
|
||||
// | "ReturnsRef": false
|
||||
// | "PhpDocComment": ""
|
||||
// | "MethodName":
|
||||
// | [*node.Identifier]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 61-73}
|
||||
// | "Value": "FunctionName"
|
||||
// | "Modifiers":
|
||||
// | [*node.Identifier]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 45-51}
|
||||
// | "Value": "public"
|
||||
// | "Params":
|
||||
// | [*node.Parameter]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 74-90}
|
||||
// | "freefloating":
|
||||
// | "OptionalType": " "
|
||||
// | "Var": " "
|
||||
// | "Variadic": false
|
||||
// | "ByRef": false
|
||||
// | "VariableType":
|
||||
// | [*name.Name]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 74-78}
|
||||
// | "NamespacedName": "Foo\\Type"
|
||||
// | "Parts":
|
||||
// | [*name.NamePart]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 74-78}
|
||||
// | "Value": "Type"
|
||||
// | "Variable":
|
||||
// | [*expr.Variable]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 79-83}
|
||||
// | "freefloating":
|
||||
// | "Dollar": "$"
|
||||
// | "VarName":
|
||||
// | [*node.Identifier]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 79-83}
|
||||
// | "Value": "var"
|
||||
// | "DefaultValue":
|
||||
// | [*expr.ConstFetch]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 86-90}
|
||||
// | "freefloating":
|
||||
// | "Start": " "
|
||||
// | "Constant":
|
||||
// | [*name.Name]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 86-90}
|
||||
// | "NamespacedName": "null"
|
||||
// | "Parts":
|
||||
// | [*name.NamePart]
|
||||
// | "Position": Pos{Line: 5-5 Pos: 86-90}
|
||||
// | "Value": "null"
|
||||
// | "Stmt":
|
||||
// | [*stmt.StmtList]
|
||||
// | "Position": Pos{Line: 6-9 Pos: 96-135}
|
||||
// | "freefloating":
|
||||
// | "Start": "\n\t\t\t\t"
|
||||
// | "Stmts": "\n\t\t\t\t"
|
||||
// | "Stmts":
|
||||
// | [*stmt.Expression]
|
||||
// | "Position": Pos{Line: 8-8 Pos: 124-129}
|
||||
// | "freefloating":
|
||||
// | "SemiColon": ";"
|
||||
// | "Start": "\n\t\t\t\t\t"
|
||||
// | "Start": "// some comment\n"
|
||||
// | "Start": "\t\t\t\t\t"
|
||||
// | "Expr":
|
||||
// | [*expr.Variable]
|
||||
// | "Position": Pos{Line: 8-8 Pos: 124-128}
|
||||
// | "freefloating":
|
||||
// | "Dollar": "$"
|
||||
// | "VarName":
|
||||
// | [*node.Identifier]
|
||||
// | "Position": Pos{Line: 8-8 Pos: 124-128}
|
||||
// | "Value": "var"
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
// Package visitor contains walker.visitor implementations
|
||||
package visitor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/walker"
|
||||
)
|
||||
|
||||
// GoDumper writes ast hierarchy to an io.Writer as native Golang struct
|
||||
type GoDumper struct {
|
||||
Writer io.Writer
|
||||
depth int
|
||||
isChildNode bool
|
||||
}
|
||||
|
||||
func printIndent(w io.Writer, d int) {
|
||||
for i := 0; i < d; i++ {
|
||||
io.WriteString(w, "\t")
|
||||
}
|
||||
}
|
||||
|
||||
// EnterNode is invoked at every node in hierarchy
|
||||
func (d *GoDumper) EnterNode(w walker.Walkable) bool {
|
||||
n := w.(node.Node)
|
||||
|
||||
nodeType := reflect.TypeOf(n).String()
|
||||
nodeType = strings.Replace(nodeType, "*", "&", 1)
|
||||
|
||||
if d.isChildNode {
|
||||
d.isChildNode = false
|
||||
} else {
|
||||
printIndent(d.Writer, d.depth)
|
||||
}
|
||||
|
||||
io.WriteString(d.Writer, nodeType+"{\n")
|
||||
|
||||
d.depth++
|
||||
|
||||
if p := n.GetPosition(); p != nil {
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprint(d.Writer, "Position: &position.Position{\n")
|
||||
d.depth++
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "StartLine: %d,\n", p.StartLine)
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "EndLine: %d,\n", p.EndLine)
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "StartPos: %d,\n", p.StartPos)
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "EndPos: %d,\n", p.EndPos)
|
||||
d.depth--
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprint(d.Writer, "},\n")
|
||||
}
|
||||
|
||||
if !n.GetFreeFloating().IsEmpty() {
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprint(d.Writer, "FreeFloating: freefloating.Collection{\n")
|
||||
d.depth++
|
||||
for key, freeFloatingStrings := range *n.GetFreeFloating() {
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "%q: []freefloating.String{\n", key)
|
||||
d.depth++
|
||||
|
||||
for _, freeFloatingString := range freeFloatingStrings {
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprint(d.Writer, "freefloating.String{\n")
|
||||
d.depth++
|
||||
|
||||
printIndent(d.Writer, d.depth)
|
||||
|
||||
switch freeFloatingString.StringType {
|
||||
case freefloating.CommentType:
|
||||
fmt.Fprint(d.Writer, "Type: freefloating.CommentType,\n")
|
||||
case freefloating.WhiteSpaceType:
|
||||
fmt.Fprint(d.Writer, "Type: freefloating.WhiteSpaceType,\n")
|
||||
case freefloating.TokenType:
|
||||
fmt.Fprint(d.Writer, "Type: freefloating.TokenType,\n")
|
||||
}
|
||||
|
||||
printIndent(d.Writer, d.depth)
|
||||
|
||||
if freeFloatingString.Position != nil {
|
||||
fmt.Fprint(d.Writer, "Position: &position.Position{\n")
|
||||
d.depth++
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "StartLine: %d,\n", freeFloatingString.Position.StartLine)
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "EndLine: %d,\n", freeFloatingString.Position.EndLine)
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "StartPos: %d,\n", freeFloatingString.Position.StartPos)
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "EndPos: %d,\n", freeFloatingString.Position.EndPos)
|
||||
d.depth--
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprint(d.Writer, "},\n")
|
||||
} else {
|
||||
fmt.Fprint(d.Writer, "Position: nil,\n")
|
||||
}
|
||||
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprintf(d.Writer, "Value: %q,\n", freeFloatingString.Value)
|
||||
|
||||
d.depth--
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprint(d.Writer, "},\n")
|
||||
}
|
||||
|
||||
d.depth--
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprint(d.Writer, "},\n")
|
||||
}
|
||||
d.depth--
|
||||
printIndent(d.Writer, d.depth)
|
||||
fmt.Fprint(d.Writer, "},\n")
|
||||
}
|
||||
|
||||
if a := n.Attributes(); len(a) > 0 {
|
||||
for key, attr := range a {
|
||||
printIndent(d.Writer, d.depth)
|
||||
switch attr.(type) {
|
||||
case string:
|
||||
fmt.Fprintf(d.Writer, "%s: %q,\n", key, attr)
|
||||
default:
|
||||
fmt.Fprintf(d.Writer, "%s: %v,\n", key, attr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// LeaveNode is invoked after node process
|
||||
func (d *GoDumper) LeaveNode(n walker.Walkable) {
|
||||
d.depth--
|
||||
printIndent(d.Writer, d.depth)
|
||||
if d.depth != 0 {
|
||||
io.WriteString(d.Writer, "},\n")
|
||||
} else {
|
||||
io.WriteString(d.Writer, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *GoDumper) EnterChildNode(key string, w walker.Walkable) {
|
||||
printIndent(d.Writer, d.depth)
|
||||
io.WriteString(d.Writer, key+": ")
|
||||
d.isChildNode = true
|
||||
}
|
||||
|
||||
func (d *GoDumper) LeaveChildNode(key string, w walker.Walkable) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
func (d *GoDumper) EnterChildList(key string, w walker.Walkable) {
|
||||
printIndent(d.Writer, d.depth)
|
||||
io.WriteString(d.Writer, key+": []node.Node{\n")
|
||||
d.depth++
|
||||
}
|
||||
|
||||
func (d *GoDumper) LeaveChildList(key string, w walker.Walkable) {
|
||||
d.depth--
|
||||
printIndent(d.Writer, d.depth)
|
||||
if d.depth != 0 {
|
||||
io.WriteString(d.Writer, "},\n")
|
||||
}
|
||||
}
|
@ -1,528 +0,0 @@
|
||||
package visitor_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/z7zmey/php-parser/php7"
|
||||
"github.com/z7zmey/php-parser/visitor"
|
||||
)
|
||||
|
||||
func ExampleGoDumper() {
|
||||
src := `<?php
|
||||
|
||||
namespace Foo {
|
||||
class Bar {
|
||||
public function FunctionName(Type $var = null)
|
||||
{
|
||||
// some comment
|
||||
$var;
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
php7parser := php7.NewParser([]byte(src), "7.4")
|
||||
php7parser.WithFreeFloating()
|
||||
php7parser.Parse()
|
||||
nodes := php7parser.GetRootNode()
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
nodes.Walk(nsResolver)
|
||||
|
||||
dumper := &visitor.GoDumper{
|
||||
Writer: os.Stdout,
|
||||
}
|
||||
nodes.Walk(dumper)
|
||||
|
||||
// Unordered output:
|
||||
// &node.Root{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 3,
|
||||
// EndLine: 11,
|
||||
// StartPos: 9,
|
||||
// EndPos: 143,
|
||||
// },
|
||||
// Stmts: []node.Node{
|
||||
// &stmt.Namespace{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 3,
|
||||
// EndLine: 11,
|
||||
// StartPos: 9,
|
||||
// EndPos: 143,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Stmts": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 10,
|
||||
// EndLine: 11,
|
||||
// StartPos: 139,
|
||||
// EndPos: 142,
|
||||
// },
|
||||
// Value: "\n\t\t",
|
||||
// },
|
||||
// },
|
||||
// "Start": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.TokenType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 1,
|
||||
// EndLine: 1,
|
||||
// StartPos: 0,
|
||||
// EndPos: 5,
|
||||
// },
|
||||
// Value: "<?php",
|
||||
// },
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 1,
|
||||
// EndLine: 3,
|
||||
// StartPos: 5,
|
||||
// EndPos: 9,
|
||||
// },
|
||||
// Value: "\n\n\t\t",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// NamespaceName: &name.Name{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 3,
|
||||
// EndLine: 3,
|
||||
// StartPos: 19,
|
||||
// EndPos: 22,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Start": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 3,
|
||||
// EndLine: 3,
|
||||
// StartPos: 18,
|
||||
// EndPos: 19,
|
||||
// },
|
||||
// Value: " ",
|
||||
// },
|
||||
// },
|
||||
// "End": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 3,
|
||||
// EndLine: 3,
|
||||
// StartPos: 22,
|
||||
// EndPos: 23,
|
||||
// },
|
||||
// Value: " ",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// Parts: []node.Node{
|
||||
// &name.NamePart{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 3,
|
||||
// EndLine: 3,
|
||||
// StartPos: 19,
|
||||
// EndPos: 22,
|
||||
// },
|
||||
// Value: "Foo",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// Stmts: []node.Node{
|
||||
// &stmt.Class{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 4,
|
||||
// EndLine: 10,
|
||||
// StartPos: 28,
|
||||
// EndPos: 139,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Start": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 3,
|
||||
// EndLine: 4,
|
||||
// StartPos: 24,
|
||||
// EndPos: 28,
|
||||
// },
|
||||
// Value: "\n\t\t\t",
|
||||
// },
|
||||
// },
|
||||
// "Name": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 4,
|
||||
// EndLine: 4,
|
||||
// StartPos: 37,
|
||||
// EndPos: 38,
|
||||
// },
|
||||
// Value: " ",
|
||||
// },
|
||||
// },
|
||||
// "Stmts": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 9,
|
||||
// EndLine: 10,
|
||||
// StartPos: 134,
|
||||
// EndPos: 138,
|
||||
// },
|
||||
// Value: "\n\t\t\t",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// PhpDocComment: "",
|
||||
// ClassName: &node.Identifier{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 4,
|
||||
// EndLine: 4,
|
||||
// StartPos: 34,
|
||||
// EndPos: 37,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Start": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 4,
|
||||
// EndLine: 4,
|
||||
// StartPos: 33,
|
||||
// EndPos: 34,
|
||||
// },
|
||||
// Value: " ",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// Value: "Bar",
|
||||
// },
|
||||
// Stmts: []node.Node{
|
||||
// &stmt.ClassMethod{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 9,
|
||||
// StartPos: 44,
|
||||
// EndPos: 134,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Start": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 4,
|
||||
// EndLine: 5,
|
||||
// StartPos: 39,
|
||||
// EndPos: 44,
|
||||
// },
|
||||
// Value: "\n\t\t\t\t",
|
||||
// },
|
||||
// },
|
||||
// "ModifierList": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 50,
|
||||
// EndPos: 51,
|
||||
// },
|
||||
// Value: " ",
|
||||
// },
|
||||
// },
|
||||
// "Function": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 59,
|
||||
// EndPos: 60,
|
||||
// },
|
||||
// Value: " ",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ReturnsRef: false,
|
||||
// PhpDocComment: "",
|
||||
// MethodName: &node.Identifier{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 60,
|
||||
// EndPos: 72,
|
||||
// },
|
||||
// Value: "FunctionName",
|
||||
// },
|
||||
// Modifiers: []node.Node{
|
||||
// &node.Identifier{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 44,
|
||||
// EndPos: 50,
|
||||
// },
|
||||
// Value: "public",
|
||||
// },
|
||||
// },
|
||||
// Params: []node.Node{
|
||||
// &node.Parameter{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 73,
|
||||
// EndPos: 89,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "OptionalType": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 77,
|
||||
// EndPos: 78,
|
||||
// },
|
||||
// Value: " ",
|
||||
// },
|
||||
// },
|
||||
// "Var": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 82,
|
||||
// EndPos: 83,
|
||||
// },
|
||||
// Value: " ",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ByRef: false,
|
||||
// Variadic: false,
|
||||
// VariableType: &name.Name{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 73,
|
||||
// EndPos: 77,
|
||||
// },
|
||||
// Parts: []node.Node{
|
||||
// &name.NamePart{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 73,
|
||||
// EndPos: 77,
|
||||
// },
|
||||
// Value: "Type",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// Variable: &expr.Variable{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 78,
|
||||
// EndPos: 82,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Dollar": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.TokenType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 78,
|
||||
// EndPos: 79,
|
||||
// },
|
||||
// Value: "$",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// VarName: &node.Identifier{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 78,
|
||||
// EndPos: 82,
|
||||
// },
|
||||
// Value: "var",
|
||||
// },
|
||||
// },
|
||||
// DefaultValue: &expr.ConstFetch{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 85,
|
||||
// EndPos: 89,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Start": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 84,
|
||||
// EndPos: 85,
|
||||
// },
|
||||
// Value: " ",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// Constant: &name.Name{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 85,
|
||||
// EndPos: 89,
|
||||
// },
|
||||
// Parts: []node.Node{
|
||||
// &name.NamePart{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 5,
|
||||
// StartPos: 85,
|
||||
// EndPos: 89,
|
||||
// },
|
||||
// Value: "null",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// Stmt: &stmt.StmtList{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 6,
|
||||
// EndLine: 9,
|
||||
// StartPos: 95,
|
||||
// EndPos: 134,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Start": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 5,
|
||||
// EndLine: 6,
|
||||
// StartPos: 90,
|
||||
// EndPos: 95,
|
||||
// },
|
||||
// Value: "\n\t\t\t\t",
|
||||
// },
|
||||
// },
|
||||
// "Stmts": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 8,
|
||||
// EndLine: 9,
|
||||
// StartPos: 128,
|
||||
// EndPos: 133,
|
||||
// },
|
||||
// Value: "\n\t\t\t\t",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// Stmts: []node.Node{
|
||||
// &stmt.Expression{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 8,
|
||||
// EndLine: 8,
|
||||
// StartPos: 123,
|
||||
// EndPos: 128,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Start": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 6,
|
||||
// EndLine: 7,
|
||||
// StartPos: 96,
|
||||
// EndPos: 102,
|
||||
// },
|
||||
// Value: "\n\t\t\t\t\t",
|
||||
// },
|
||||
// freefloating.String{
|
||||
// Type: freefloating.CommentType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 7,
|
||||
// EndLine: 7,
|
||||
// StartPos: 102,
|
||||
// EndPos: 118,
|
||||
// },
|
||||
// Value: "// some comment\n",
|
||||
// },
|
||||
// freefloating.String{
|
||||
// Type: freefloating.WhiteSpaceType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 8,
|
||||
// EndLine: 8,
|
||||
// StartPos: 118,
|
||||
// EndPos: 123,
|
||||
// },
|
||||
// Value: "\t\t\t\t\t",
|
||||
// },
|
||||
// },
|
||||
// "SemiColon": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.TokenType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 8,
|
||||
// EndLine: 8,
|
||||
// StartPos: 127,
|
||||
// EndPos: 128,
|
||||
// },
|
||||
// Value: ";",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// Expr: &expr.Variable{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 8,
|
||||
// EndLine: 8,
|
||||
// StartPos: 123,
|
||||
// EndPos: 127,
|
||||
// },
|
||||
// FreeFloating: freefloating.Collection{
|
||||
// "Dollar": []freefloating.String{
|
||||
// freefloating.String{
|
||||
// Type: freefloating.TokenType,
|
||||
// Position: &position.Position{
|
||||
// StartLine: 8,
|
||||
// EndLine: 8,
|
||||
// StartPos: 123,
|
||||
// EndPos: 124,
|
||||
// },
|
||||
// Value: "$",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// VarName: &node.Identifier{
|
||||
// Position: &position.Position{
|
||||
// StartLine: 8,
|
||||
// EndLine: 8,
|
||||
// StartPos: 123,
|
||||
// EndPos: 127,
|
||||
// },
|
||||
// Value: "var",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
// Package visitor contains walker.visitor implementations
|
||||
package visitor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/walker"
|
||||
)
|
||||
|
||||
type JsonDumper struct {
|
||||
Writer io.Writer
|
||||
NsResolver *NamespaceResolver
|
||||
isChildNode bool
|
||||
isNotFirstNode bool
|
||||
}
|
||||
|
||||
// EnterNode is invoked at every node in hierarchy
|
||||
func (d *JsonDumper) EnterNode(w walker.Walkable) bool {
|
||||
n := w.(node.Node)
|
||||
|
||||
nodeType := reflect.TypeOf(n).String()
|
||||
|
||||
if d.isChildNode {
|
||||
d.isChildNode = false
|
||||
} else if d.isNotFirstNode {
|
||||
fmt.Fprint(d.Writer, ",")
|
||||
} else {
|
||||
d.isNotFirstNode = true
|
||||
}
|
||||
|
||||
fmt.Fprintf(d.Writer, "{%q:%q", "type", nodeType)
|
||||
|
||||
if p := n.GetPosition(); p != nil {
|
||||
p := n.GetPosition()
|
||||
fmt.Fprintf(d.Writer, ",%q:{%q:%d,%q:%d,%q:%d,%q:%d}",
|
||||
"position",
|
||||
"startPos", p.StartPos,
|
||||
"endPos", p.EndPos,
|
||||
"startLine", p.StartLine,
|
||||
"endLine", p.EndLine)
|
||||
}
|
||||
|
||||
if d.NsResolver != nil {
|
||||
if namespacedName, ok := d.NsResolver.ResolvedNames[n]; ok {
|
||||
fmt.Fprintf(d.Writer, ",%q:%q", "namespacedName", namespacedName)
|
||||
}
|
||||
}
|
||||
|
||||
if !n.GetFreeFloating().IsEmpty() {
|
||||
fmt.Fprintf(d.Writer, ",%q:{", "freefloating")
|
||||
|
||||
var freefloatingStringsKeys []int
|
||||
for key := range *n.GetFreeFloating() {
|
||||
freefloatingStringsKeys = append(freefloatingStringsKeys, int(key))
|
||||
}
|
||||
|
||||
sort.Ints(freefloatingStringsKeys)
|
||||
|
||||
i := 0
|
||||
for _, k := range freefloatingStringsKeys {
|
||||
key := freefloating.Position(k)
|
||||
freeFloatingStrings := (*n.GetFreeFloating())[key]
|
||||
if i != 0 {
|
||||
fmt.Fprint(d.Writer, ",")
|
||||
}
|
||||
i++
|
||||
|
||||
fmt.Fprintf(d.Writer, "%q: [", key.String())
|
||||
|
||||
j := 0
|
||||
for _, freeFloatingString := range freeFloatingStrings {
|
||||
if j != 0 {
|
||||
fmt.Fprint(d.Writer, ",")
|
||||
}
|
||||
j++
|
||||
|
||||
switch freeFloatingString.StringType {
|
||||
case freefloating.CommentType:
|
||||
fmt.Fprintf(d.Writer, "{%q:%q,%q:%q}", "type", "freefloating.CommentType", "value", freeFloatingString.Value)
|
||||
case freefloating.WhiteSpaceType:
|
||||
fmt.Fprintf(d.Writer, "{%q:%q,%q:%q}", "type", "freefloating.WhiteSpaceType", "value", freeFloatingString.Value)
|
||||
case freefloating.TokenType:
|
||||
fmt.Fprintf(d.Writer, "{%q:%q,%q:%q}", "type", "freefloating.TokenType", "value", freeFloatingString.Value)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprint(d.Writer, "]")
|
||||
}
|
||||
|
||||
fmt.Fprint(d.Writer, "}")
|
||||
}
|
||||
|
||||
if a := n.Attributes(); len(a) > 0 {
|
||||
var attributes []string
|
||||
for key := range n.Attributes() {
|
||||
attributes = append(attributes, key)
|
||||
}
|
||||
|
||||
sort.Strings(attributes)
|
||||
|
||||
for _, attributeName := range attributes {
|
||||
attr := a[attributeName]
|
||||
switch attr.(type) {
|
||||
case string:
|
||||
fmt.Fprintf(d.Writer, ",\"%s\":%q", attributeName, attr)
|
||||
default:
|
||||
fmt.Fprintf(d.Writer, ",\"%s\":%v", attributeName, attr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// LeaveNode is invoked after node process
|
||||
func (d *JsonDumper) LeaveNode(n walker.Walkable) {
|
||||
fmt.Fprint(d.Writer, "}")
|
||||
}
|
||||
|
||||
func (d *JsonDumper) EnterChildNode(key string, w walker.Walkable) {
|
||||
fmt.Fprintf(d.Writer, ",%q:", key)
|
||||
d.isChildNode = true
|
||||
}
|
||||
|
||||
func (d *JsonDumper) LeaveChildNode(key string, w walker.Walkable) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
func (d *JsonDumper) EnterChildList(key string, w walker.Walkable) {
|
||||
fmt.Fprintf(d.Writer, ",%q:[", key)
|
||||
d.isNotFirstNode = false
|
||||
|
||||
}
|
||||
|
||||
func (d *JsonDumper) LeaveChildList(key string, w walker.Walkable) {
|
||||
fmt.Fprint(d.Writer, "]")
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package visitor_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/z7zmey/php-parser/php7"
|
||||
"github.com/z7zmey/php-parser/visitor"
|
||||
)
|
||||
|
||||
func ExampleJsonDumper() {
|
||||
src := `<?php
|
||||
|
||||
namespace Foo {
|
||||
class Bar {
|
||||
public function FunctionName(Type $var = null)
|
||||
{
|
||||
// some comment
|
||||
// second comment
|
||||
$var1;
|
||||
$var2;
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
php7parser := php7.NewParser([]byte(src), "7.4")
|
||||
php7parser.WithFreeFloating()
|
||||
php7parser.Parse()
|
||||
nodes := php7parser.GetRootNode()
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
nodes.Walk(nsResolver)
|
||||
|
||||
dumper := &visitor.JsonDumper{
|
||||
Writer: os.Stdout,
|
||||
NsResolver: nsResolver,
|
||||
}
|
||||
nodes.Walk(dumper)
|
||||
|
||||
// Output:
|
||||
// {"type":"*node.Root","position":{"startPos":9,"endPos":179,"startLine":3,"endLine":13},"Stmts":[{"type":"*stmt.Namespace","position":{"startPos":9,"endPos":179,"startLine":3,"endLine":13},"freefloating":{"Start": [{"type":"freefloating.TokenType","value":"<?php"},{"type":"freefloating.WhiteSpaceType","value":"\n\n\t\t"}],"Stmts": [{"type":"freefloating.WhiteSpaceType","value":"\n\t\t"}]},"NamespaceName":{"type":"*name.Name","position":{"startPos":19,"endPos":22,"startLine":3,"endLine":3},"freefloating":{"Start": [{"type":"freefloating.WhiteSpaceType","value":" "}],"End": [{"type":"freefloating.WhiteSpaceType","value":" "}]},"Parts":[{"type":"*name.NamePart","position":{"startPos":19,"endPos":22,"startLine":3,"endLine":3},"Value":"Foo"}]},"Stmts":[{"type":"*stmt.Class","position":{"startPos":28,"endPos":175,"startLine":4,"endLine":12},"namespacedName":"Foo\\Bar","freefloating":{"Start": [{"type":"freefloating.WhiteSpaceType","value":"\n\t\t\t"}],"Name": [{"type":"freefloating.WhiteSpaceType","value":" "}],"Stmts": [{"type":"freefloating.WhiteSpaceType","value":"\n\t\t\t"}]},"PhpDocComment":"","ClassName":{"type":"*node.Identifier","position":{"startPos":34,"endPos":37,"startLine":4,"endLine":4},"freefloating":{"Start": [{"type":"freefloating.WhiteSpaceType","value":" "}]},"Value":"Bar"},"Stmts":[{"type":"*stmt.ClassMethod","position":{"startPos":44,"endPos":170,"startLine":5,"endLine":11},"freefloating":{"Start": [{"type":"freefloating.WhiteSpaceType","value":"\n\t\t\t\t"}],"Function": [{"type":"freefloating.WhiteSpaceType","value":" "}],"ModifierList": [{"type":"freefloating.WhiteSpaceType","value":" "}]},"PhpDocComment":"","ReturnsRef":false,"MethodName":{"type":"*node.Identifier","position":{"startPos":60,"endPos":72,"startLine":5,"endLine":5},"Value":"FunctionName"},"Modifiers":[{"type":"*node.Identifier","position":{"startPos":44,"endPos":50,"startLine":5,"endLine":5},"Value":"public"}],"Params":[{"type":"*node.Parameter","position":{"startPos":73,"endPos":89,"startLine":5,"endLine":5},"freefloating":{"Var": [{"type":"freefloating.WhiteSpaceType","value":" "}],"OptionalType": [{"type":"freefloating.WhiteSpaceType","value":" "}]},"ByRef":false,"Variadic":false,"VariableType":{"type":"*name.Name","position":{"startPos":73,"endPos":77,"startLine":5,"endLine":5},"namespacedName":"Foo\\Type","Parts":[{"type":"*name.NamePart","position":{"startPos":73,"endPos":77,"startLine":5,"endLine":5},"Value":"Type"}]},"Variable":{"type":"*expr.Variable","position":{"startPos":78,"endPos":82,"startLine":5,"endLine":5},"freefloating":{"Dollar": [{"type":"freefloating.TokenType","value":"$"}]},"VarName":{"type":"*node.Identifier","position":{"startPos":78,"endPos":82,"startLine":5,"endLine":5},"Value":"var"}},"DefaultValue":{"type":"*expr.ConstFetch","position":{"startPos":85,"endPos":89,"startLine":5,"endLine":5},"freefloating":{"Start": [{"type":"freefloating.WhiteSpaceType","value":" "}]},"Constant":{"type":"*name.Name","position":{"startPos":85,"endPos":89,"startLine":5,"endLine":5},"namespacedName":"null","Parts":[{"type":"*name.NamePart","position":{"startPos":85,"endPos":89,"startLine":5,"endLine":5},"Value":"null"}]}}}],"Stmt":{"type":"*stmt.StmtList","position":{"startPos":95,"endPos":170,"startLine":6,"endLine":11},"freefloating":{"Start": [{"type":"freefloating.WhiteSpaceType","value":"\n\t\t\t\t"}],"Stmts": [{"type":"freefloating.WhiteSpaceType","value":"\n\t\t\t\t"}]},"Stmts":[{"type":"*stmt.Expression","position":{"startPos":146,"endPos":152,"startLine":9,"endLine":9},"freefloating":{"Start": [{"type":"freefloating.WhiteSpaceType","value":"\n\t\t\t\t\t"},{"type":"freefloating.CommentType","value":"// some comment\n"},{"type":"freefloating.WhiteSpaceType","value":"\t\t\t\t\t"},{"type":"freefloating.CommentType","value":"// second comment\n"},{"type":"freefloating.WhiteSpaceType","value":"\t\t\t\t\t"}],"SemiColon": [{"type":"freefloating.TokenType","value":";"}]},"Expr":{"type":"*expr.Variable","position":{"startPos":146,"endPos":151,"startLine":9,"endLine":9},"freefloating":{"Dollar": [{"type":"freefloating.TokenType","value":"$"}]},"VarName":{"type":"*node.Identifier","position":{"startPos":146,"endPos":151,"startLine":9,"endLine":9},"Value":"var1"}}},{"type":"*stmt.Expression","position":{"startPos":158,"endPos":164,"startLine":10,"endLine":10},"freefloating":{"Start": [{"type":"freefloating.WhiteSpaceType","value":"\n\t\t\t\t\t"}],"SemiColon": [{"type":"freefloating.TokenType","value":";"}]},"Expr":{"type":"*expr.Variable","position":{"startPos":158,"endPos":163,"startLine":10,"endLine":10},"freefloating":{"Dollar": [{"type":"freefloating.TokenType","value":"$"}]},"VarName":{"type":"*node.Identifier","position":{"startPos":158,"endPos":163,"startLine":10,"endLine":10},"Value":"var2"}}}]}}]}]}]}
|
||||
}
|
@ -1,392 +0,0 @@
|
||||
// Package visitor contains walker.visitor implementations
|
||||
package visitor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/z7zmey/php-parser/node/expr"
|
||||
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/node/name"
|
||||
"github.com/z7zmey/php-parser/node/stmt"
|
||||
"github.com/z7zmey/php-parser/walker"
|
||||
)
|
||||
|
||||
// NamespaceResolver visitor
|
||||
type NamespaceResolver struct {
|
||||
Namespace *Namespace
|
||||
ResolvedNames map[node.Node]string
|
||||
}
|
||||
|
||||
// NewNamespaceResolver NamespaceResolver type constructor
|
||||
func NewNamespaceResolver() *NamespaceResolver {
|
||||
return &NamespaceResolver{
|
||||
Namespace: NewNamespace(""),
|
||||
ResolvedNames: map[node.Node]string{},
|
||||
}
|
||||
}
|
||||
|
||||
// EnterNode is invoked at every node in heirerchy
|
||||
func (nsr *NamespaceResolver) EnterNode(w walker.Walkable) bool {
|
||||
switch n := w.(type) {
|
||||
case *stmt.Namespace:
|
||||
if n.NamespaceName == nil {
|
||||
nsr.Namespace = NewNamespace("")
|
||||
} else {
|
||||
NSParts := n.NamespaceName.(*name.Name).Parts
|
||||
nsr.Namespace = NewNamespace(concatNameParts(NSParts))
|
||||
}
|
||||
|
||||
case *stmt.UseList:
|
||||
useType := ""
|
||||
if n.UseType != nil {
|
||||
useType = n.UseType.(*node.Identifier).Value
|
||||
}
|
||||
|
||||
for _, nn := range n.Uses {
|
||||
nsr.AddAlias(useType, nn, nil)
|
||||
}
|
||||
|
||||
// no reason to iterate into depth
|
||||
return false
|
||||
|
||||
case *stmt.GroupUse:
|
||||
useType := ""
|
||||
if n.UseType != nil {
|
||||
useType = n.UseType.(*node.Identifier).Value
|
||||
}
|
||||
|
||||
for _, nn := range n.UseList {
|
||||
nsr.AddAlias(useType, nn, n.Prefix.(*name.Name).Parts)
|
||||
}
|
||||
|
||||
// no reason to iterate into depth
|
||||
return false
|
||||
|
||||
case *stmt.Class:
|
||||
if n.Extends != nil {
|
||||
nsr.ResolveName(n.Extends.ClassName, "")
|
||||
}
|
||||
|
||||
if n.Implements != nil {
|
||||
for _, interfaceName := range n.Implements.InterfaceNames {
|
||||
nsr.ResolveName(interfaceName, "")
|
||||
}
|
||||
}
|
||||
|
||||
if n.ClassName != nil {
|
||||
nsr.AddNamespacedName(n, n.ClassName.(*node.Identifier).Value)
|
||||
}
|
||||
|
||||
case *stmt.Interface:
|
||||
if n.Extends != nil {
|
||||
for _, interfaceName := range n.Extends.InterfaceNames {
|
||||
nsr.ResolveName(interfaceName, "")
|
||||
}
|
||||
}
|
||||
|
||||
nsr.AddNamespacedName(n, n.InterfaceName.(*node.Identifier).Value)
|
||||
|
||||
case *stmt.Trait:
|
||||
nsr.AddNamespacedName(n, n.TraitName.(*node.Identifier).Value)
|
||||
|
||||
case *stmt.Function:
|
||||
nsr.AddNamespacedName(n, n.FunctionName.(*node.Identifier).Value)
|
||||
|
||||
for _, parameter := range n.Params {
|
||||
nsr.ResolveType(parameter.(*node.Parameter).VariableType)
|
||||
}
|
||||
|
||||
if n.ReturnType != nil {
|
||||
nsr.ResolveType(n.ReturnType)
|
||||
}
|
||||
|
||||
case *stmt.ClassMethod:
|
||||
for _, parameter := range n.Params {
|
||||
nsr.ResolveType(parameter.(*node.Parameter).VariableType)
|
||||
}
|
||||
|
||||
if n.ReturnType != nil {
|
||||
nsr.ResolveType(n.ReturnType)
|
||||
}
|
||||
|
||||
case *expr.Closure:
|
||||
for _, parameter := range n.Params {
|
||||
nsr.ResolveType(parameter.(*node.Parameter).VariableType)
|
||||
}
|
||||
|
||||
if n.ReturnType != nil {
|
||||
nsr.ResolveType(n.ReturnType)
|
||||
}
|
||||
|
||||
case *stmt.ConstList:
|
||||
for _, constant := range n.Consts {
|
||||
nsr.AddNamespacedName(constant, constant.(*stmt.Constant).ConstantName.(*node.Identifier).Value)
|
||||
}
|
||||
|
||||
case *expr.StaticCall:
|
||||
nsr.ResolveName(n.Class, "")
|
||||
|
||||
case *expr.StaticPropertyFetch:
|
||||
nsr.ResolveName(n.Class, "")
|
||||
|
||||
case *expr.ClassConstFetch:
|
||||
nsr.ResolveName(n.Class, "")
|
||||
|
||||
case *expr.New:
|
||||
nsr.ResolveName(n.Class, "")
|
||||
|
||||
case *expr.InstanceOf:
|
||||
nsr.ResolveName(n.Class, "")
|
||||
|
||||
case *stmt.Catch:
|
||||
for _, t := range n.Types {
|
||||
nsr.ResolveName(t, "")
|
||||
}
|
||||
|
||||
case *expr.FunctionCall:
|
||||
nsr.ResolveName(n.Function, "function")
|
||||
|
||||
case *expr.ConstFetch:
|
||||
nsr.ResolveName(n.Constant, "const")
|
||||
|
||||
case *stmt.TraitUse:
|
||||
for _, t := range n.Traits {
|
||||
nsr.ResolveName(t, "")
|
||||
}
|
||||
|
||||
if adaptationList, ok := n.TraitAdaptationList.(*stmt.TraitAdaptationList); ok {
|
||||
for _, a := range adaptationList.Adaptations {
|
||||
switch aa := a.(type) {
|
||||
case *stmt.TraitUsePrecedence:
|
||||
refTrait := aa.Ref.(*stmt.TraitMethodRef).Trait
|
||||
if refTrait != nil {
|
||||
nsr.ResolveName(refTrait, "")
|
||||
}
|
||||
for _, insteadOf := range aa.Insteadof {
|
||||
nsr.ResolveName(insteadOf, "")
|
||||
}
|
||||
|
||||
case *stmt.TraitUseAlias:
|
||||
refTrait := aa.Ref.(*stmt.TraitMethodRef).Trait
|
||||
if refTrait != nil {
|
||||
nsr.ResolveName(refTrait, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// LeaveNode is invoked after node process
|
||||
func (nsr *NamespaceResolver) LeaveNode(w walker.Walkable) {
|
||||
switch n := w.(type) {
|
||||
case *stmt.Namespace:
|
||||
if n.Stmts != nil {
|
||||
nsr.Namespace = NewNamespace("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (nsr *NamespaceResolver) EnterChildNode(key string, w walker.Walkable) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
func (nsr *NamespaceResolver) LeaveChildNode(key string, w walker.Walkable) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
func (nsr *NamespaceResolver) EnterChildList(key string, w walker.Walkable) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
func (nsr *NamespaceResolver) LeaveChildList(key string, w walker.Walkable) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// AddAlias adds a new alias
|
||||
func (nsr *NamespaceResolver) AddAlias(useType string, nn node.Node, prefix []node.Node) {
|
||||
switch use := nn.(type) {
|
||||
case *stmt.Use:
|
||||
if use.UseType != nil {
|
||||
useType = use.UseType.(*node.Identifier).Value
|
||||
}
|
||||
|
||||
useNameParts := use.Use.(*name.Name).Parts
|
||||
var alias string
|
||||
if use.Alias == nil {
|
||||
alias = useNameParts[len(useNameParts)-1].(*name.NamePart).Value
|
||||
} else {
|
||||
alias = use.Alias.(*node.Identifier).Value
|
||||
}
|
||||
|
||||
nsr.Namespace.AddAlias(useType, concatNameParts(prefix, useNameParts), alias)
|
||||
}
|
||||
}
|
||||
|
||||
// AddNamespacedName adds namespaced name by node
|
||||
func (nsr *NamespaceResolver) AddNamespacedName(nn node.Node, nodeName string) {
|
||||
if nsr.Namespace.Namespace == "" {
|
||||
nsr.ResolvedNames[nn] = nodeName
|
||||
} else {
|
||||
nsr.ResolvedNames[nn] = nsr.Namespace.Namespace + "\\" + nodeName
|
||||
}
|
||||
}
|
||||
|
||||
// ResolveName adds a resolved fully qualified name by node
|
||||
func (nsr *NamespaceResolver) ResolveName(nameNode node.Node, aliasType string) {
|
||||
resolved, err := nsr.Namespace.ResolveName(nameNode, aliasType)
|
||||
if err == nil {
|
||||
nsr.ResolvedNames[nameNode] = resolved
|
||||
}
|
||||
}
|
||||
|
||||
// ResolveType adds a resolved fully qualified type name
|
||||
func (nsr *NamespaceResolver) ResolveType(n node.Node) {
|
||||
switch nn := n.(type) {
|
||||
case *node.Nullable:
|
||||
nsr.ResolveType(nn.Expr)
|
||||
case name.Names:
|
||||
nsr.ResolveName(n, "")
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace context
|
||||
type Namespace struct {
|
||||
Namespace string
|
||||
Aliases map[string]map[string]string
|
||||
}
|
||||
|
||||
// NewNamespace constructor
|
||||
func NewNamespace(NSName string) *Namespace {
|
||||
return &Namespace{
|
||||
Namespace: NSName,
|
||||
Aliases: map[string]map[string]string{
|
||||
"": {},
|
||||
"const": {},
|
||||
"function": {},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AddAlias adds a new alias
|
||||
func (ns *Namespace) AddAlias(aliasType string, aliasName string, alias string) {
|
||||
aliasType = strings.ToLower(aliasType)
|
||||
|
||||
if aliasType == "const" {
|
||||
ns.Aliases[aliasType][alias] = aliasName
|
||||
} else {
|
||||
ns.Aliases[aliasType][strings.ToLower(alias)] = aliasName
|
||||
}
|
||||
}
|
||||
|
||||
// ResolveName returns a resolved fully qualified name
|
||||
func (ns *Namespace) ResolveName(nameNode node.Node, aliasType string) (string, error) {
|
||||
switch n := nameNode.(type) {
|
||||
case *name.FullyQualified:
|
||||
// Fully qualifid name is already resolved
|
||||
return concatNameParts(n.Parts), nil
|
||||
|
||||
case *name.Relative:
|
||||
if ns.Namespace == "" {
|
||||
return concatNameParts(n.Parts), nil
|
||||
}
|
||||
return ns.Namespace + "\\" + concatNameParts(n.Parts), nil
|
||||
|
||||
case *name.Name:
|
||||
if aliasType == "const" && len(n.Parts) == 1 {
|
||||
part := strings.ToLower(n.Parts[0].(*name.NamePart).Value)
|
||||
if part == "true" || part == "false" || part == "null" {
|
||||
return part, nil
|
||||
}
|
||||
}
|
||||
|
||||
if aliasType == "" && len(n.Parts) == 1 {
|
||||
part := strings.ToLower(n.Parts[0].(*name.NamePart).Value)
|
||||
|
||||
switch part {
|
||||
case "self":
|
||||
fallthrough
|
||||
case "static":
|
||||
fallthrough
|
||||
case "parent":
|
||||
fallthrough
|
||||
case "int":
|
||||
fallthrough
|
||||
case "float":
|
||||
fallthrough
|
||||
case "bool":
|
||||
fallthrough
|
||||
case "string":
|
||||
fallthrough
|
||||
case "void":
|
||||
fallthrough
|
||||
case "iterable":
|
||||
fallthrough
|
||||
case "object":
|
||||
return part, nil
|
||||
}
|
||||
}
|
||||
|
||||
aliasName, err := ns.ResolveAlias(nameNode, aliasType)
|
||||
if err != nil {
|
||||
// resolve as relative name if alias not found
|
||||
if ns.Namespace == "" {
|
||||
return concatNameParts(n.Parts), nil
|
||||
}
|
||||
return ns.Namespace + "\\" + concatNameParts(n.Parts), nil
|
||||
}
|
||||
|
||||
if len(n.Parts) > 1 {
|
||||
// if name qualified, replace first part by alias
|
||||
return aliasName + "\\" + concatNameParts(n.Parts[1:]), nil
|
||||
}
|
||||
|
||||
return aliasName, nil
|
||||
}
|
||||
|
||||
return "", errors.New("must be instance of name.Names")
|
||||
}
|
||||
|
||||
// ResolveAlias returns alias or error if not found
|
||||
func (ns *Namespace) ResolveAlias(nameNode node.Node, aliasType string) (string, error) {
|
||||
aliasType = strings.ToLower(aliasType)
|
||||
nameParts := nameNode.(*name.Name).Parts
|
||||
|
||||
firstPartStr := nameParts[0].(*name.NamePart).Value
|
||||
|
||||
if len(nameParts) > 1 { // resolve aliases for qualified names, always against class alias type
|
||||
firstPartStr = strings.ToLower(firstPartStr)
|
||||
aliasType = ""
|
||||
} else {
|
||||
if aliasType != "const" { // constants are case-sensitive
|
||||
firstPartStr = strings.ToLower(firstPartStr)
|
||||
}
|
||||
}
|
||||
|
||||
aliasName, ok := ns.Aliases[aliasType][firstPartStr]
|
||||
if !ok {
|
||||
return "", errors.New("Not found")
|
||||
}
|
||||
|
||||
return aliasName, nil
|
||||
}
|
||||
|
||||
func concatNameParts(parts ...[]node.Node) string {
|
||||
str := ""
|
||||
|
||||
for _, p := range parts {
|
||||
for _, n := range p {
|
||||
if str == "" {
|
||||
str = n.(*name.NamePart).Value
|
||||
} else {
|
||||
str = str + "\\" + n.(*name.NamePart).Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
@ -1,976 +0,0 @@
|
||||
package visitor_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/node/expr"
|
||||
"github.com/z7zmey/php-parser/node/name"
|
||||
"github.com/z7zmey/php-parser/node/scalar"
|
||||
"github.com/z7zmey/php-parser/node/stmt"
|
||||
"github.com/z7zmey/php-parser/visitor"
|
||||
)
|
||||
|
||||
func TestResolveStaticCall(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAB,
|
||||
},
|
||||
},
|
||||
},
|
||||
&expr.StaticCall{
|
||||
Class: nameBC,
|
||||
Call: &node.Identifier{Value: "foo"},
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameBC: "A\\B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveStaticPropertyFetch(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAB,
|
||||
},
|
||||
},
|
||||
},
|
||||
&expr.StaticPropertyFetch{
|
||||
Class: nameBC,
|
||||
Property: &node.Identifier{Value: "foo"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameBC: "A\\B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveClassConstFetch(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAB,
|
||||
},
|
||||
},
|
||||
},
|
||||
&expr.ClassConstFetch{
|
||||
Class: nameBC,
|
||||
ConstantName: &node.Identifier{Value: "FOO"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameBC: "A\\B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveNew(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAB,
|
||||
},
|
||||
},
|
||||
},
|
||||
&expr.New{
|
||||
Class: nameBC,
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameBC: "A\\B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveInstanceOf(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAB,
|
||||
},
|
||||
},
|
||||
},
|
||||
&expr.InstanceOf{
|
||||
Expr: &expr.Variable{VarName: &node.Identifier{Value: "foo"}},
|
||||
Class: nameBC,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameBC: "A\\B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveInstanceCatch(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
nameDE := &name.Name{Parts: []node.Node{&name.NamePart{Value: "D"}, &name.NamePart{Value: "E"}}}
|
||||
nameF := &name.Name{Parts: []node.Node{&name.NamePart{Value: "F"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAB,
|
||||
},
|
||||
&stmt.Use{
|
||||
Use: nameDE,
|
||||
Alias: &node.Identifier{Value: "F"},
|
||||
},
|
||||
},
|
||||
},
|
||||
&stmt.Try{
|
||||
Stmts: []node.Node{},
|
||||
Catches: []node.Node{
|
||||
&stmt.Catch{
|
||||
Types: []node.Node{
|
||||
nameBC,
|
||||
nameF,
|
||||
},
|
||||
Variable: &expr.Variable{VarName: &node.Identifier{Value: "foo"}},
|
||||
Stmts: []node.Node{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameBC: "A\\B\\C",
|
||||
nameF: "D\\E",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveFunctionCall(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
UseType: &node.Identifier{Value: "function"},
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAB,
|
||||
},
|
||||
},
|
||||
},
|
||||
&expr.FunctionCall{
|
||||
Function: nameB,
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameB: "A\\B",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveConstFetch(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
UseType: &node.Identifier{Value: "const"},
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAB,
|
||||
},
|
||||
},
|
||||
},
|
||||
&expr.ConstFetch{
|
||||
Constant: nameB,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameB: "A\\B",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveGroupUse(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBD := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "D"}}}
|
||||
nameE := &name.Name{Parts: []node.Node{&name.NamePart{Value: "E"}}}
|
||||
nameC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "C"}}}
|
||||
nameF := &name.Name{Parts: []node.Node{&name.NamePart{Value: "F"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.GroupUse{
|
||||
Prefix: nameAB,
|
||||
UseList: []node.Node{
|
||||
&stmt.Use{
|
||||
UseType: &node.Identifier{Value: "Function"},
|
||||
Use: nameF,
|
||||
},
|
||||
&stmt.Use{
|
||||
UseType: &node.Identifier{Value: "const"},
|
||||
Use: nameC,
|
||||
},
|
||||
},
|
||||
},
|
||||
&stmt.GroupUse{
|
||||
Prefix: nameBD,
|
||||
UseType: &node.Identifier{Value: "Function"},
|
||||
UseList: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameE,
|
||||
},
|
||||
},
|
||||
},
|
||||
&expr.ConstFetch{
|
||||
Constant: nameC,
|
||||
},
|
||||
&expr.FunctionCall{
|
||||
Function: nameF,
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
&expr.FunctionCall{
|
||||
Function: nameE,
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameC: "A\\B\\C",
|
||||
nameF: "A\\B\\F",
|
||||
nameE: "B\\D\\E",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveTraitUse(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}}}
|
||||
nameD := &name.Name{Parts: []node.Node{&name.NamePart{Value: "D"}}}
|
||||
|
||||
fullyQualifiedNameB := &name.FullyQualified{Parts: []node.Node{&name.NamePart{Value: "B"}}}
|
||||
fullyQualifiedNameBC := &name.FullyQualified{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
relativeNameB := &name.Relative{Parts: []node.Node{&name.NamePart{Value: "B"}}}
|
||||
relativeNameBC := &name.Relative{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAB,
|
||||
},
|
||||
},
|
||||
},
|
||||
&stmt.TraitUse{
|
||||
Traits: []node.Node{
|
||||
nameB,
|
||||
relativeNameB,
|
||||
},
|
||||
TraitAdaptationList: &stmt.TraitAdaptationList{
|
||||
Adaptations: []node.Node{
|
||||
&stmt.TraitUsePrecedence{
|
||||
Ref: &stmt.TraitMethodRef{
|
||||
Trait: fullyQualifiedNameB,
|
||||
Method: &node.Identifier{Value: "foo"},
|
||||
},
|
||||
Insteadof: []node.Node{fullyQualifiedNameBC},
|
||||
},
|
||||
&stmt.TraitUseAlias{
|
||||
Ref: &stmt.TraitMethodRef{
|
||||
Trait: relativeNameBC,
|
||||
Method: &node.Identifier{Value: "foo"},
|
||||
},
|
||||
Alias: &node.Identifier{Value: "bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
&stmt.TraitUse{
|
||||
Traits: []node.Node{
|
||||
nameD,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameB: "A\\B",
|
||||
nameD: "D",
|
||||
relativeNameB: "B",
|
||||
fullyQualifiedNameB: "B",
|
||||
fullyQualifiedNameBC: "B\\C",
|
||||
relativeNameBC: "B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveClassName(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
class := &stmt.Class{
|
||||
PhpDocComment: "",
|
||||
ClassName: &node.Identifier{Value: "A"},
|
||||
Extends: &stmt.ClassExtends{
|
||||
ClassName: nameAB,
|
||||
},
|
||||
Implements: &stmt.ClassImplements{
|
||||
InterfaceNames: []node.Node{
|
||||
nameBC,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
class,
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
class: "A",
|
||||
nameAB: "A\\B",
|
||||
nameBC: "B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveInterfaceName(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
interfaceNode := &stmt.Interface{
|
||||
PhpDocComment: "",
|
||||
InterfaceName: &node.Identifier{Value: "A"},
|
||||
Extends: &stmt.InterfaceExtends{
|
||||
InterfaceNames: []node.Node{
|
||||
nameAB,
|
||||
nameBC,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
interfaceNode,
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
interfaceNode: "A",
|
||||
nameAB: "A\\B",
|
||||
nameBC: "B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveTraitName(t *testing.T) {
|
||||
traitNode := &stmt.Trait{
|
||||
PhpDocComment: "",
|
||||
TraitName: &node.Identifier{Value: "A"},
|
||||
Stmts: []node.Node{},
|
||||
}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
traitNode,
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
traitNode: "A",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveFunctionName(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
functionNode := &stmt.Function{
|
||||
ReturnsRef: false,
|
||||
PhpDocComment: "",
|
||||
FunctionName: &node.Identifier{Value: "A"},
|
||||
Params: []node.Node{
|
||||
&node.Parameter{
|
||||
ByRef: false,
|
||||
Variadic: false,
|
||||
VariableType: nameAB,
|
||||
Variable: &expr.Variable{VarName: &node.Identifier{Value: "foo"}},
|
||||
},
|
||||
},
|
||||
ReturnType: &node.Nullable{Expr: nameBC},
|
||||
Stmts: []node.Node{},
|
||||
}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
functionNode,
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
functionNode: "A",
|
||||
nameAB: "A\\B",
|
||||
nameBC: "B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveMethodName(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
methodNode := &stmt.ClassMethod{
|
||||
ReturnsRef: false,
|
||||
PhpDocComment: "",
|
||||
MethodName: &node.Identifier{Value: "A"},
|
||||
Params: []node.Node{
|
||||
&node.Parameter{
|
||||
ByRef: false,
|
||||
Variadic: false,
|
||||
VariableType: nameAB,
|
||||
Variable: &expr.Variable{VarName: &node.Identifier{Value: "foo"}},
|
||||
},
|
||||
},
|
||||
ReturnType: &node.Nullable{Expr: nameBC},
|
||||
Stmt: &stmt.StmtList{
|
||||
Stmts: []node.Node{},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameAB: "A\\B",
|
||||
nameBC: "B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
methodNode.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveClosureName(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
|
||||
|
||||
closureNode := &expr.Closure{
|
||||
ReturnsRef: false,
|
||||
Static: false,
|
||||
PhpDocComment: "",
|
||||
Params: []node.Node{
|
||||
&node.Parameter{
|
||||
ByRef: false,
|
||||
Variadic: false,
|
||||
VariableType: nameAB,
|
||||
Variable: &expr.Variable{VarName: &node.Identifier{Value: "foo"}},
|
||||
},
|
||||
},
|
||||
ReturnType: &node.Nullable{Expr: nameBC},
|
||||
Stmts: []node.Node{},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
nameAB: "A\\B",
|
||||
nameBC: "B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
closureNode.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveConstantsName(t *testing.T) {
|
||||
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
|
||||
constantB := &stmt.Constant{
|
||||
PhpDocComment: "",
|
||||
ConstantName: &node.Identifier{Value: "B"},
|
||||
Expr: &scalar.Lnumber{Value: "1"},
|
||||
}
|
||||
constantC := &stmt.Constant{
|
||||
PhpDocComment: "",
|
||||
ConstantName: &node.Identifier{Value: "C"},
|
||||
Expr: &scalar.Lnumber{Value: "1"},
|
||||
}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.Namespace{
|
||||
NamespaceName: nameAB,
|
||||
},
|
||||
&stmt.ConstList{
|
||||
Consts: []node.Node{
|
||||
constantB,
|
||||
constantC,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
constantB: "A\\B\\B",
|
||||
constantC: "A\\B\\C",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveNamespaces(t *testing.T) {
|
||||
namespaceAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
|
||||
namespaceCD := &name.Name{Parts: []node.Node{&name.NamePart{Value: "C"}, &name.NamePart{Value: "D"}}}
|
||||
|
||||
nameAC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "C"}}}
|
||||
nameCF := &name.Name{Parts: []node.Node{&name.NamePart{Value: "C"}, &name.NamePart{Value: "F"}}}
|
||||
nameFG := &name.Name{Parts: []node.Node{&name.NamePart{Value: "F"}, &name.NamePart{Value: "G"}}}
|
||||
relativeNameCE := &name.Relative{Parts: []node.Node{&name.NamePart{Value: "C"}, &name.NamePart{Value: "E"}}}
|
||||
|
||||
constantB := &stmt.Constant{
|
||||
PhpDocComment: "",
|
||||
ConstantName: &node.Identifier{Value: "B"},
|
||||
Expr: &scalar.Lnumber{Value: "1"},
|
||||
}
|
||||
constantC := &stmt.Constant{
|
||||
PhpDocComment: "",
|
||||
ConstantName: &node.Identifier{Value: "C"},
|
||||
Expr: &scalar.Lnumber{Value: "1"},
|
||||
}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.Namespace{
|
||||
NamespaceName: namespaceAB,
|
||||
},
|
||||
&stmt.ConstList{
|
||||
Consts: []node.Node{
|
||||
constantB,
|
||||
constantC,
|
||||
},
|
||||
},
|
||||
&expr.StaticCall{
|
||||
Class: nameFG,
|
||||
Call: &node.Identifier{Value: "foo"},
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
&stmt.Namespace{
|
||||
Stmts: []node.Node{},
|
||||
},
|
||||
&stmt.Namespace{
|
||||
NamespaceName: namespaceCD,
|
||||
Stmts: []node.Node{
|
||||
&stmt.UseList{
|
||||
Uses: []node.Node{
|
||||
&stmt.Use{
|
||||
Use: nameAC,
|
||||
},
|
||||
},
|
||||
},
|
||||
&expr.StaticCall{
|
||||
Class: relativeNameCE,
|
||||
Call: &node.Identifier{Value: "foo"},
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
&expr.StaticCall{
|
||||
Class: nameCF,
|
||||
Call: &node.Identifier{Value: "foo"},
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
constantB: "A\\B\\B",
|
||||
constantC: "A\\B\\C",
|
||||
nameFG: "A\\B\\F\\G",
|
||||
relativeNameCE: "C\\D\\C\\E",
|
||||
nameCF: "A\\C\\F",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestResolveStaticCallDinamicClassName(t *testing.T) {
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&expr.StaticCall{
|
||||
Class: &expr.Variable{VarName: &node.Identifier{Value: "foo"}},
|
||||
Call: &node.Identifier{Value: "foo"},
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestDoNotResolveReservedConstants(t *testing.T) {
|
||||
namespaceName := &name.Name{Parts: []node.Node{&name.NamePart{Value: "Foo"}}}
|
||||
|
||||
constantTrue := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "True"},
|
||||
},
|
||||
}
|
||||
|
||||
constantFalse := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "False"},
|
||||
},
|
||||
}
|
||||
|
||||
constantNull := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "NULL"},
|
||||
},
|
||||
}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.Namespace{
|
||||
NamespaceName: namespaceName,
|
||||
},
|
||||
&stmt.Expression{
|
||||
Expr: &expr.ConstFetch{
|
||||
Constant: constantTrue,
|
||||
},
|
||||
},
|
||||
&stmt.Expression{
|
||||
Expr: &expr.ConstFetch{
|
||||
Constant: constantFalse,
|
||||
},
|
||||
},
|
||||
&stmt.Expression{
|
||||
Expr: &expr.ConstFetch{
|
||||
Constant: constantNull,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
constantTrue: "true",
|
||||
constantFalse: "false",
|
||||
constantNull: "null",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestDoNotResolveReservedNames(t *testing.T) {
|
||||
|
||||
nameInt := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "int"},
|
||||
},
|
||||
}
|
||||
|
||||
nameFloat := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "float"},
|
||||
},
|
||||
}
|
||||
|
||||
nameBool := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "bool"},
|
||||
},
|
||||
}
|
||||
|
||||
nameString := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "string"},
|
||||
},
|
||||
}
|
||||
|
||||
nameVoid := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "void"},
|
||||
},
|
||||
}
|
||||
|
||||
nameIterable := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "iterable"},
|
||||
},
|
||||
}
|
||||
|
||||
nameObject := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "object"},
|
||||
},
|
||||
}
|
||||
|
||||
function := &stmt.Function{
|
||||
FunctionName: &node.Identifier{Value: "bar"},
|
||||
Params: []node.Node{
|
||||
&node.Parameter{
|
||||
VariableType: nameInt,
|
||||
Variable: &expr.Variable{
|
||||
VarName: &node.Identifier{Value: "Int"},
|
||||
},
|
||||
},
|
||||
&node.Parameter{
|
||||
VariableType: nameFloat,
|
||||
Variable: &expr.Variable{
|
||||
VarName: &node.Identifier{Value: "Float"},
|
||||
},
|
||||
},
|
||||
&node.Parameter{
|
||||
VariableType: nameBool,
|
||||
Variable: &expr.Variable{
|
||||
VarName: &node.Identifier{Value: "Bool"},
|
||||
},
|
||||
},
|
||||
&node.Parameter{
|
||||
VariableType: nameString,
|
||||
Variable: &expr.Variable{
|
||||
VarName: &node.Identifier{Value: "String"},
|
||||
},
|
||||
},
|
||||
&node.Parameter{
|
||||
VariableType: nameVoid,
|
||||
Variable: &expr.Variable{
|
||||
VarName: &node.Identifier{Value: "Void"},
|
||||
},
|
||||
},
|
||||
&node.Parameter{
|
||||
VariableType: nameIterable,
|
||||
Variable: &expr.Variable{
|
||||
VarName: &node.Identifier{Value: "Iterable"},
|
||||
},
|
||||
},
|
||||
&node.Parameter{
|
||||
VariableType: nameObject,
|
||||
Variable: &expr.Variable{
|
||||
VarName: &node.Identifier{Value: "Object"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.Namespace{
|
||||
NamespaceName: &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "Foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
function,
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
function: "Foo\\bar",
|
||||
nameInt: "int",
|
||||
nameFloat: "float",
|
||||
nameBool: "bool",
|
||||
nameString: "string",
|
||||
nameVoid: "void",
|
||||
nameIterable: "iterable",
|
||||
nameObject: "object",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
||||
|
||||
func TestDoNotResolveReservedSpecialNames(t *testing.T) {
|
||||
|
||||
nameSelf := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "Self"},
|
||||
},
|
||||
}
|
||||
|
||||
nameStatic := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "Static"},
|
||||
},
|
||||
}
|
||||
|
||||
nameParent := &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "Parent"},
|
||||
},
|
||||
}
|
||||
|
||||
cls := &stmt.Class{
|
||||
ClassName: &node.Identifier{Value: "Bar"},
|
||||
Stmts: []node.Node{
|
||||
&stmt.Expression{
|
||||
Expr: &expr.StaticCall{
|
||||
Class: nameSelf,
|
||||
Call: &node.Identifier{Value: "func"},
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
},
|
||||
&stmt.Expression{
|
||||
Expr: &expr.StaticCall{
|
||||
Class: nameStatic,
|
||||
Call: &node.Identifier{Value: "func"},
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
},
|
||||
&stmt.Expression{
|
||||
Expr: &expr.StaticCall{
|
||||
Class: nameParent,
|
||||
Call: &node.Identifier{Value: "func"},
|
||||
ArgumentList: &node.ArgumentList{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ast := &stmt.StmtList{
|
||||
Stmts: []node.Node{
|
||||
&stmt.Namespace{
|
||||
NamespaceName: &name.Name{
|
||||
Parts: []node.Node{
|
||||
&name.NamePart{Value: "Foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
cls,
|
||||
},
|
||||
}
|
||||
|
||||
expected := map[node.Node]string{
|
||||
cls: "Foo\\Bar",
|
||||
nameSelf: "self",
|
||||
nameStatic: "static",
|
||||
nameParent: "parent",
|
||||
}
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
ast.Walk(nsResolver)
|
||||
|
||||
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
// Package visitor contains walker.visitor implementations
|
||||
package visitor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/z7zmey/php-parser/freefloating"
|
||||
"github.com/z7zmey/php-parser/node"
|
||||
"github.com/z7zmey/php-parser/walker"
|
||||
)
|
||||
|
||||
type PrettyJsonDumper struct {
|
||||
Writer io.Writer
|
||||
NsResolver *NamespaceResolver
|
||||
depth int
|
||||
isChildNode bool
|
||||
isNotFirstNode bool
|
||||
}
|
||||
|
||||
func NewPrettyJsonDumper(Writer io.Writer, NsResolver *NamespaceResolver) *PrettyJsonDumper {
|
||||
return &PrettyJsonDumper{
|
||||
Writer: Writer,
|
||||
NsResolver: NsResolver,
|
||||
depth: 0,
|
||||
isChildNode: false,
|
||||
isNotFirstNode: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *PrettyJsonDumper) printIndent(w io.Writer) {
|
||||
for i := 0; i < d.depth; i++ {
|
||||
fmt.Fprint(d.Writer, " ")
|
||||
}
|
||||
}
|
||||
|
||||
// EnterNode is invoked at every node in hierarchy
|
||||
func (d *PrettyJsonDumper) EnterNode(w walker.Walkable) bool {
|
||||
n := w.(node.Node)
|
||||
|
||||
nodeType := reflect.TypeOf(n).String()
|
||||
|
||||
if d.isChildNode {
|
||||
d.isChildNode = false
|
||||
} else if d.isNotFirstNode {
|
||||
fmt.Fprint(d.Writer, ",\n")
|
||||
d.printIndent(d.Writer)
|
||||
} else {
|
||||
d.printIndent(d.Writer)
|
||||
d.isNotFirstNode = true
|
||||
}
|
||||
|
||||
fmt.Fprint(d.Writer, "{\n")
|
||||
d.depth++
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: %q", "type", nodeType)
|
||||
|
||||
if p := n.GetPosition(); p != nil {
|
||||
fmt.Fprint(d.Writer, ",\n")
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: {\n", "position")
|
||||
d.depth++
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: %d,\n", "startPos", p.StartPos)
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: %d,\n", "endPos", p.EndPos)
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: %d,\n", "startLine", p.StartLine)
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: %d\n", "endLine", p.EndLine)
|
||||
d.depth--
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprint(d.Writer, "}")
|
||||
}
|
||||
|
||||
if d.NsResolver != nil {
|
||||
if namespacedName, ok := d.NsResolver.ResolvedNames[n]; ok {
|
||||
fmt.Fprint(d.Writer, ",\n")
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "\"namespacedName\": %q", namespacedName)
|
||||
}
|
||||
}
|
||||
|
||||
if !n.GetFreeFloating().IsEmpty() {
|
||||
fmt.Fprint(d.Writer, ",\n")
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprint(d.Writer, "\"freefloating\": {\n")
|
||||
d.depth++
|
||||
i := 0
|
||||
for key, freeFloatingStrings := range *n.GetFreeFloating() {
|
||||
if i != 0 {
|
||||
fmt.Fprint(d.Writer, ",\n")
|
||||
}
|
||||
i++
|
||||
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: [\n", key)
|
||||
d.depth++
|
||||
|
||||
j := 0
|
||||
for _, freeFloatingString := range freeFloatingStrings {
|
||||
if j != 0 {
|
||||
fmt.Fprint(d.Writer, ",\n")
|
||||
}
|
||||
j++
|
||||
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprint(d.Writer, "{\n")
|
||||
d.depth++
|
||||
d.printIndent(d.Writer)
|
||||
switch freeFloatingString.StringType {
|
||||
case freefloating.CommentType:
|
||||
fmt.Fprintf(d.Writer, "%q: %q,\n", "type", "freefloating.CommentType")
|
||||
case freefloating.WhiteSpaceType:
|
||||
fmt.Fprintf(d.Writer, "%q: %q,\n", "type", "freefloating.WhiteSpaceType")
|
||||
case freefloating.TokenType:
|
||||
fmt.Fprintf(d.Writer, "%q: %q,\n", "type", "freefloating.TokenType")
|
||||
}
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: %q\n", "value", freeFloatingString.Value)
|
||||
d.depth--
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprint(d.Writer, "}")
|
||||
}
|
||||
|
||||
d.depth--
|
||||
fmt.Fprint(d.Writer, "\n")
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprint(d.Writer, "]")
|
||||
}
|
||||
d.depth--
|
||||
fmt.Fprint(d.Writer, "\n")
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprint(d.Writer, "}")
|
||||
}
|
||||
|
||||
if a := n.Attributes(); len(a) > 0 {
|
||||
for key, attr := range a {
|
||||
fmt.Fprint(d.Writer, ",\n")
|
||||
d.printIndent(d.Writer)
|
||||
switch attr.(type) {
|
||||
case string:
|
||||
fmt.Fprintf(d.Writer, "\"%s\": %q", key, attr)
|
||||
default:
|
||||
fmt.Fprintf(d.Writer, "\"%s\": %v", key, attr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// LeaveNode is invoked after node process
|
||||
func (d *PrettyJsonDumper) LeaveNode(n walker.Walkable) {
|
||||
d.depth--
|
||||
fmt.Fprint(d.Writer, "\n")
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprint(d.Writer, "}")
|
||||
}
|
||||
|
||||
func (d *PrettyJsonDumper) EnterChildNode(key string, w walker.Walkable) {
|
||||
fmt.Fprint(d.Writer, ",\n")
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: ", key)
|
||||
d.isChildNode = true
|
||||
}
|
||||
|
||||
func (d *PrettyJsonDumper) LeaveChildNode(key string, w walker.Walkable) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
func (d *PrettyJsonDumper) EnterChildList(key string, w walker.Walkable) {
|
||||
fmt.Fprint(d.Writer, ",\n")
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprintf(d.Writer, "%q: [\n", key)
|
||||
d.depth++
|
||||
|
||||
d.isNotFirstNode = false
|
||||
}
|
||||
|
||||
func (d *PrettyJsonDumper) LeaveChildList(key string, w walker.Walkable) {
|
||||
d.depth--
|
||||
fmt.Fprint(d.Writer, "\n")
|
||||
d.printIndent(d.Writer)
|
||||
fmt.Fprint(d.Writer, "]")
|
||||
}
|
@ -1,509 +0,0 @@
|
||||
package visitor_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/z7zmey/php-parser/php7"
|
||||
"github.com/z7zmey/php-parser/visitor"
|
||||
)
|
||||
|
||||
func ExamplePrettyJsonDumper() {
|
||||
src := `<?php
|
||||
|
||||
namespace Foo {
|
||||
class Bar {
|
||||
public function FunctionName(Type $var = null)
|
||||
{
|
||||
// some comment
|
||||
// second comment
|
||||
$var;
|
||||
}
|
||||
}
|
||||
|
||||
function foo() {
|
||||
;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
php7parser := php7.NewParser([]byte(src), "7.4")
|
||||
php7parser.WithFreeFloating()
|
||||
php7parser.Parse()
|
||||
nodes := php7parser.GetRootNode()
|
||||
|
||||
nsResolver := visitor.NewNamespaceResolver()
|
||||
nodes.Walk(nsResolver)
|
||||
|
||||
dumper := visitor.NewPrettyJsonDumper(os.Stdout, nsResolver)
|
||||
nodes.Walk(dumper)
|
||||
|
||||
// Unordered output:
|
||||
// {
|
||||
// "type": "*node.Root",
|
||||
// "position": {
|
||||
// "startPos": 9,
|
||||
// "endPos": 198,
|
||||
// "startLine": 3,
|
||||
// "endLine": 16
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "End": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "Stmts": [
|
||||
// {
|
||||
// "type": "*stmt.Namespace",
|
||||
// "position": {
|
||||
// "startPos": 9,
|
||||
// "endPos": 198,
|
||||
// "startLine": 3,
|
||||
// "endLine": 16
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.TokenType",
|
||||
// "value": "<?php"
|
||||
// },
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\n\t\t"
|
||||
// }
|
||||
// ],
|
||||
// "Stmts": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "NamespaceName": {
|
||||
// "type": "*name.Name",
|
||||
// "position": {
|
||||
// "startPos": 19,
|
||||
// "endPos": 22,
|
||||
// "startLine": 3,
|
||||
// "endLine": 3
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ],
|
||||
// "End": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "Parts": [
|
||||
// {
|
||||
// "type": "*name.NamePart",
|
||||
// "position": {
|
||||
// "startPos": 19,
|
||||
// "endPos": 22,
|
||||
// "startLine": 3,
|
||||
// "endLine": 3
|
||||
// },
|
||||
// "Value": "Foo"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "Stmts": [
|
||||
// {
|
||||
// "type": "*stmt.Class",
|
||||
// "position": {
|
||||
// "startPos": 28,
|
||||
// "endPos": 162,
|
||||
// "startLine": 4,
|
||||
// "endLine": 11
|
||||
// },
|
||||
// "namespacedName": "Foo\\Bar",
|
||||
// "freefloating": {
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t\t"
|
||||
// }
|
||||
// ],
|
||||
// "Name": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ],
|
||||
// "Stmts": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t\t"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "PhpDocComment": "",
|
||||
// "ClassName": {
|
||||
// "type": "*node.Identifier",
|
||||
// "position": {
|
||||
// "startPos": 34,
|
||||
// "endPos": 37,
|
||||
// "startLine": 4,
|
||||
// "endLine": 4
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "Value": "Bar"
|
||||
// },
|
||||
// "Stmts": [
|
||||
// {
|
||||
// "type": "*stmt.ClassMethod",
|
||||
// "position": {
|
||||
// "startPos": 44,
|
||||
// "endPos": 157,
|
||||
// "startLine": 5,
|
||||
// "endLine": 10
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t\t\t"
|
||||
// }
|
||||
// ],
|
||||
// "ModifierList": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ],
|
||||
// "Function": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "ReturnsRef": false,
|
||||
// "PhpDocComment": "",
|
||||
// "MethodName": {
|
||||
// "type": "*node.Identifier",
|
||||
// "position": {
|
||||
// "startPos": 60,
|
||||
// "endPos": 72,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "Value": "FunctionName"
|
||||
// },
|
||||
// "Modifiers": [
|
||||
// {
|
||||
// "type": "*node.Identifier",
|
||||
// "position": {
|
||||
// "startPos": 44,
|
||||
// "endPos": 50,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "Value": "public"
|
||||
// }
|
||||
// ],
|
||||
// "Params": [
|
||||
// {
|
||||
// "type": "*node.Parameter",
|
||||
// "position": {
|
||||
// "startPos": 73,
|
||||
// "endPos": 89,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "OptionalType": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ],
|
||||
// "Var": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "ByRef": false,
|
||||
// "Variadic": false,
|
||||
// "VariableType": {
|
||||
// "type": "*name.Name",
|
||||
// "position": {
|
||||
// "startPos": 73,
|
||||
// "endPos": 77,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "namespacedName": "Foo\\Type",
|
||||
// "Parts": [
|
||||
// {
|
||||
// "type": "*name.NamePart",
|
||||
// "position": {
|
||||
// "startPos": 73,
|
||||
// "endPos": 77,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "Value": "Type"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "Variable": {
|
||||
// "type": "*expr.Variable",
|
||||
// "position": {
|
||||
// "startPos": 78,
|
||||
// "endPos": 82,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Dollar": [
|
||||
// {
|
||||
// "type": "freefloating.TokenType",
|
||||
// "value": "$"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "VarName": {
|
||||
// "type": "*node.Identifier",
|
||||
// "position": {
|
||||
// "startPos": 78,
|
||||
// "endPos": 82,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "Value": "var"
|
||||
// }
|
||||
// },
|
||||
// "DefaultValue": {
|
||||
// "type": "*expr.ConstFetch",
|
||||
// "position": {
|
||||
// "startPos": 85,
|
||||
// "endPos": 89,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "Constant": {
|
||||
// "type": "*name.Name",
|
||||
// "position": {
|
||||
// "startPos": 85,
|
||||
// "endPos": 89,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "namespacedName": "null",
|
||||
// "Parts": [
|
||||
// {
|
||||
// "type": "*name.NamePart",
|
||||
// "position": {
|
||||
// "startPos": 85,
|
||||
// "endPos": 89,
|
||||
// "startLine": 5,
|
||||
// "endLine": 5
|
||||
// },
|
||||
// "Value": "null"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ],
|
||||
// "Stmt": {
|
||||
// "type": "*stmt.StmtList",
|
||||
// "position": {
|
||||
// "startPos": 95,
|
||||
// "endPos": 157,
|
||||
// "startLine": 6,
|
||||
// "endLine": 10
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Stmts": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t\t\t"
|
||||
// }
|
||||
// ],
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t\t\t"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "Stmts": [
|
||||
// {
|
||||
// "type": "*stmt.Expression",
|
||||
// "position": {
|
||||
// "startPos": 146,
|
||||
// "endPos": 151,
|
||||
// "startLine": 9,
|
||||
// "endLine": 9
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t\t\t\t"
|
||||
// },
|
||||
// {
|
||||
// "type": "freefloating.CommentType",
|
||||
// "value": "// some comment\n"
|
||||
// },
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\t\t\t\t\t"
|
||||
// },
|
||||
// {
|
||||
// "type": "freefloating.CommentType",
|
||||
// "value": "// second comment\n"
|
||||
// },
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\t\t\t\t\t"
|
||||
// }
|
||||
// ],
|
||||
// "SemiColon": [
|
||||
// {
|
||||
// "type": "freefloating.TokenType",
|
||||
// "value": ";"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "Expr": {
|
||||
// "type": "*expr.Variable",
|
||||
// "position": {
|
||||
// "startPos": 146,
|
||||
// "endPos": 150,
|
||||
// "startLine": 9,
|
||||
// "endLine": 9
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Dollar": [
|
||||
// {
|
||||
// "type": "freefloating.TokenType",
|
||||
// "value": "$"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "VarName": {
|
||||
// "type": "*node.Identifier",
|
||||
// "position": {
|
||||
// "startPos": 146,
|
||||
// "endPos": 150,
|
||||
// "startLine": 9,
|
||||
// "endLine": 9
|
||||
// },
|
||||
// "Value": "var"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "type": "*stmt.Function",
|
||||
// "position": {
|
||||
// "startPos": 167,
|
||||
// "endPos": 194,
|
||||
// "startLine": 13,
|
||||
// "endLine": 15
|
||||
// },
|
||||
// "namespacedName": "Foo\\foo",
|
||||
// "freefloating": {
|
||||
// "Params": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ],
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\n\t\t\t"
|
||||
// }
|
||||
// ],
|
||||
// "Stmts": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t\t"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "ReturnsRef": false,
|
||||
// "PhpDocComment": "",
|
||||
// "FunctionName": {
|
||||
// "type": "*node.Identifier",
|
||||
// "position": {
|
||||
// "startPos": 176,
|
||||
// "endPos": 179,
|
||||
// "startLine": 13,
|
||||
// "endLine": 13
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": " "
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "Value": "foo"
|
||||
// },
|
||||
// "Stmts": [
|
||||
// {
|
||||
// "type": "*stmt.Nop",
|
||||
// "position": {
|
||||
// "startPos": 188,
|
||||
// "endPos": 189,
|
||||
// "startLine": 14,
|
||||
// "endLine": 14
|
||||
// },
|
||||
// "freefloating": {
|
||||
// "Start": [
|
||||
// {
|
||||
// "type": "freefloating.WhiteSpaceType",
|
||||
// "value": "\n\t\t\t\t"
|
||||
// }
|
||||
// ],
|
||||
// "SemiColon": [
|
||||
// {
|
||||
// "type": "freefloating.TokenType",
|
||||
// "value": ";"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
// Package walker declares walking behavior
|
||||
package walker
|
||||
|
||||
// Walkable interface
|
||||
//
|
||||
// Every node must implement this interface
|
||||
type Walkable interface {
|
||||
Walk(v Visitor)
|
||||
}
|
||||
|
||||
// Visitor interface
|
||||
type Visitor interface {
|
||||
EnterNode(w Walkable) bool
|
||||
LeaveNode(w Walkable)
|
||||
|
||||
EnterChildNode(key string, w Walkable)
|
||||
LeaveChildNode(key string, w Walkable)
|
||||
|
||||
EnterChildList(key string, w Walkable)
|
||||
LeaveChildList(key string, w Walkable)
|
||||
}
|
Loading…
Reference in New Issue
Block a user