php-parser/visitor/go_dumper.go
2019-02-25 15:01:57 +02:00

173 lines
4.4 KiB
Go

// 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")
}
}