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 | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										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) | ||||
| } | ||||
| @ -35,14 +35,14 @@ type Lexer struct { | ||||
| 	top          int | ||||
| 	heredocLabel []byte | ||||
| 
 | ||||
| 	TokenPool        *TokenPool | ||||
| 	FreeFloating     []freefloating.String | ||||
| 	WithFreeFloating bool | ||||
| 	PhpDocComment    string | ||||
| 	lastToken        *Token | ||||
| 	Errors           []*errors.Error | ||||
| 	NewLines         NewLines | ||||
| 	PHPVersion       string | ||||
| 	TokenPool     *TokenPool | ||||
| 	Tokens        []token.Token | ||||
| 	WithTokens    bool | ||||
| 	PhpDocComment string | ||||
| 	lastToken     *Token | ||||
| 	Errors        []*errors.Error | ||||
| 	NewLines      NewLines | ||||
| 	PHPVersion    string | ||||
| } | ||||
| 
 | ||||
| func (l *Lexer) ReturnTokenToPool(t *Token) { | ||||
| @ -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], | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -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") | ||||
| @ -90,14 +89,14 @@ func (v *testVisitor) Identifier(_ *ast.Identifier) { | ||||
| 	fmt.Fprintln(os.Stdout, "=>", strings.Repeat("  ", v.depth-1), "*ast.Identifier") | ||||
| } | ||||
| 
 | ||||
| func (v *testVisitor) ArgumentList(_ *ast.ArgumentList)  { | ||||
| func (v *testVisitor) ArgumentList(_ *ast.ArgumentList) { | ||||
| 	fmt.Fprintln(os.Stdout, "=>", strings.Repeat("  ", v.depth-1), "*ast.ArgumentList") | ||||
| } | ||||
| 
 | ||||
| func (v *testVisitor) Argument(_ *ast.Argument)  { | ||||
| func (v *testVisitor) Argument(_ *ast.Argument) { | ||||
| 	fmt.Fprintln(os.Stdout, "=>", strings.Repeat("  ", v.depth-1), "*ast.Argument") | ||||
| } | ||||
| 
 | ||||
| func (v *testVisitor) ScalarDnumber(_ *ast.ScalarDnumber)  { | ||||
| func (v *testVisitor) ScalarDnumber(_ *ast.ScalarDnumber) { | ||||
| 	fmt.Fprintln(os.Stdout, "=>", strings.Repeat("  ", v.depth-1), "*ast.ScalarDnumber") | ||||
| } | ||||
|  | ||||
| @ -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) | ||||
| } | ||||
|  | ||||
| @ -73,7 +73,7 @@ func (v *Dump) EnterNode(n ast.Vertex) bool { | ||||
| 	} | ||||
| 
 | ||||
| 	n.Accept(v) | ||||
| 	 | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user