php-parser/visitor/pretty_json_dumper.go

171 lines
4.1 KiB
Go

// Package visitor contains walker.visitor implementations
package visitor
import (
"fmt"
"io"
"reflect"
"github.com/z7zmey/php-parser/meta"
"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 mm := n.GetMeta(); len(*mm) > 0 {
fmt.Fprint(d.Writer, ",\n")
d.printIndent(d.Writer)
fmt.Fprint(d.Writer, "\"meta\": [\n")
d.depth++
for k, m := range *mm {
if k != 0 {
fmt.Fprint(d.Writer, ",\n")
}
d.printIndent(d.Writer)
fmt.Fprint(d.Writer, "{\n")
d.depth++
d.printIndent(d.Writer)
switch m.Type {
case meta.CommentType:
fmt.Fprintf(d.Writer, "%q: %q,\n", "type", "*meta.CommentType")
case meta.WhiteSpaceType:
fmt.Fprintf(d.Writer, "%q: %q,\n", "type", "*meta.WhiteSpaceType")
case meta.TokenType:
fmt.Fprintf(d.Writer, "%q: %q,\n", "type", "*meta.TokenType")
}
d.printIndent(d.Writer)
fmt.Fprintf(d.Writer, "%q: %q,\n", "value", m.String())
d.printIndent(d.Writer)
fmt.Fprintf(d.Writer, "%q: %q\n", "tokenName", m.TokenName.String())
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, "]")
}
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, "]")
}