#30 created json dumper

This commit is contained in:
z7zmey 2018-06-19 23:55:12 +03:00
parent dd572a8fed
commit 09c984ebdb
8 changed files with 700 additions and 92 deletions

View File

@ -47,9 +47,17 @@ CLI
---
```
php-parser [-php5 -noDump] <path> ...
php-parser [flags] <path> ...
```
| flag | type | description |
|-------|------|----------------------------------------------|
| -d |string| dump format: [custom, go, json, pretty-json] |
| -p | bool | show positions |
| -c | bool | show comments |
| -r | bool | resolve names |
| -php5 | bool | parse as PHP5 |
Dump AST to stdout.
Example

55
main.go
View File

@ -17,11 +17,18 @@ import (
var wg sync.WaitGroup
var usePhp5 *bool
var noDump *bool
var dumpType string
var showPositions *bool
var showComments *bool
var showResolvedNs *bool
func main() {
usePhp5 = flag.Bool("php5", false, "use PHP5 parserWorker")
noDump = flag.Bool("noDump", false, "disable dumping to stdout")
usePhp5 = flag.Bool("php5", false, "parse as PHP5")
showPositions = flag.Bool("p", false, "show positions")
showComments = flag.Bool("c", false, "show comments")
showResolvedNs = flag.Bool("r", false, "resolve names")
flag.StringVar(&dumpType, "d", "", "dump format: [custom, go, json, pretty_json]")
flag.Parse()
pathCh := make(chan string)
@ -95,19 +102,53 @@ func printer(result <-chan parser.Parser) {
fmt.Println(e)
}
if !*noDump {
nsResolver := visitor.NewNamespaceResolver()
var nsResolver *visitor.NamespaceResolver
if *showResolvedNs {
nsResolver = visitor.NewNamespaceResolver()
parserWorker.GetRootNode().Walk(nsResolver)
}
var comments parser.Comments
if *showComments {
comments = parserWorker.GetComments()
}
var positions parser.Positions
if *showPositions {
positions = parserWorker.GetPositions()
}
switch dumpType {
case "custom":
dumper := &visitor.Dumper{
Writer: os.Stdout,
Indent: "| ",
Comments: parserWorker.GetComments(),
Positions: parserWorker.GetPositions(),
Comments: comments,
Positions: positions,
NsResolver: nsResolver,
}
parserWorker.GetRootNode().Walk(dumper)
case "json":
dumper := &visitor.JsonDumper{
Writer: os.Stdout,
Comments: comments,
Positions: positions,
NsResolver: nsResolver,
}
parserWorker.GetRootNode().Walk(dumper)
case "pretty_json":
dumper := &visitor.PrettyJsonDumper{
Writer: os.Stdout,
Comments: comments,
Positions: positions,
NsResolver: nsResolver,
}
parserWorker.GetRootNode().Walk(dumper)
case "go":
dumper := &visitor.GoDumper{Writer: os.Stdout}
parserWorker.GetRootNode().Walk(dumper)
}
wg.Done()
}
}

View File

@ -32,13 +32,13 @@ func (d *Dumper) EnterNode(w walker.Walkable) bool {
if d.Positions != nil {
if p := d.Positions[n]; p != nil {
fmt.Fprintf(d.Writer, "%v\"Position\": %s;\n", d.Indent+" ", *p)
fmt.Fprintf(d.Writer, "%v\"Position\": %s\n", d.Indent+" ", *p)
}
}
if d.NsResolver != nil {
if namespacedName, ok := d.NsResolver.ResolvedNames[n]; ok {
fmt.Fprintf(d.Writer, "%v\"NamespacedName\": %s;\n", d.Indent+" ", namespacedName)
fmt.Fprintf(d.Writer, "%v\"NamespacedName\": %q\n", d.Indent+" ", namespacedName)
}
}
@ -53,7 +53,12 @@ func (d *Dumper) EnterNode(w walker.Walkable) bool {
if a := n.Attributes(); len(a) > 0 {
for key, attr := range a {
fmt.Fprintf(d.Writer, "%v\"%v\": %v;\n", d.Indent+" ", key, attr)
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)
}
}
}

View File

@ -40,83 +40,83 @@ func ExampleDumper() {
// Unordered output:
// | [*node.Root]
//| "Position": Pos{Line: 3-11 Pos: 10-143};
// | "Position": Pos{Line: 3-11 Pos: 10-143}
// | "Stmts":
// | [*stmt.Namespace]
//| "Position": Pos{Line: 3-11 Pos: 10-143};
// | "Position": Pos{Line: 3-11 Pos: 10-143}
// | "NamespaceName":
// | [*name.Name]
//| "Position": Pos{Line: 3-3 Pos: 20-22};
// | "Position": Pos{Line: 3-3 Pos: 20-22}
// | "Parts":
// | [*name.NamePart]
//| "Position": Pos{Line: 3-3 Pos: 20-22};
//| "Value": Foo;
// | "Position": Pos{Line: 3-3 Pos: 20-22}
// | "Value": "Foo"
// | "Stmts":
// | [*stmt.Class]
//| "Position": Pos{Line: 4-10 Pos: 29-139};
//| "NamespacedName": Foo\Bar;
//| "PhpDocComment": ;
// | "Position": Pos{Line: 4-10 Pos: 29-139}
// | "NamespacedName": "Foo\\Bar"
// | "PhpDocComment": ""
// | "ClassName":
// | [*node.Identifier]
//| "Position": Pos{Line: 4-4 Pos: 35-37};
//| "Value": Bar;
// | "Position": Pos{Line: 4-4 Pos: 35-37}
// | "Value": "Bar"
// | "Stmts":
// | [*stmt.ClassMethod]
//| "Position": Pos{Line: 5-9 Pos: 45-134};
//| "ReturnsRef": false;
//| "PhpDocComment": ;
// | "Position": Pos{Line: 5-9 Pos: 45-134}
// | "ReturnsRef": false
// | "PhpDocComment": ""
// | "MethodName":
// | [*node.Identifier]
//| "Position": Pos{Line: 5-5 Pos: 61-72};
//| "Value": FunctionName;
// | "Position": Pos{Line: 5-5 Pos: 61-72}
// | "Value": "FunctionName"
// | "Modifiers":
// | [*node.Identifier]
//| "Position": Pos{Line: 5-5 Pos: 45-50};
//| "Value": public;
// | "Position": Pos{Line: 5-5 Pos: 45-50}
// | "Value": "public"
// | "Params":
// | [*node.Parameter]
//| "Position": Pos{Line: 5-5 Pos: 74-89};
//| "ByRef": false;
//| "Variadic": false;
// | "Position": Pos{Line: 5-5 Pos: 74-89}
// | "Variadic": false
// | "ByRef": false
// | "VariableType":
// | [*name.Name]
//| "Position": Pos{Line: 5-5 Pos: 74-77};
//| "NamespacedName": Foo\Type;
// | "Position": Pos{Line: 5-5 Pos: 74-77}
// | "NamespacedName": "Foo\\Type"
// | "Parts":
// | [*name.NamePart]
//| "Position": Pos{Line: 5-5 Pos: 74-77};
//| "Value": Type;
// | "Position": Pos{Line: 5-5 Pos: 74-77}
// | "Value": "Type"
// | "Variable":
// | [*expr.Variable]
//| "Position": Pos{Line: 5-5 Pos: 79-82};
// | "Position": Pos{Line: 5-5 Pos: 79-82}
// | "VarName":
// | [*node.Identifier]
//| "Position": Pos{Line: 5-5 Pos: 79-82};
//| "Value": var;
// | "Position": Pos{Line: 5-5 Pos: 79-82}
// | "Value": "var"
// | "DefaultValue":
// | [*expr.ConstFetch]
//| "Position": Pos{Line: 5-5 Pos: 86-89};
// | "Position": Pos{Line: 5-5 Pos: 86-89}
// | "Constant":
// | [*name.Name]
//| "Position": Pos{Line: 5-5 Pos: 86-89};
//| "NamespacedName": null;
// | "Position": Pos{Line: 5-5 Pos: 86-89}
// | "NamespacedName": "null"
// | "Parts":
// | [*name.NamePart]
//| "Position": Pos{Line: 5-5 Pos: 86-89};
//| "Value": null;
// | "Position": Pos{Line: 5-5 Pos: 86-89}
// | "Value": "null"
// | "Stmt":
// | [*stmt.StmtList]
//| "Position": Pos{Line: 6-9 Pos: 96-134};
// | "Position": Pos{Line: 6-9 Pos: 96-134}
// | "Stmts":
// | [*stmt.Expression]
//| "Position": Pos{Line: 8-8 Pos: 124-128};
// | "Position": Pos{Line: 8-8 Pos: 124-128}
// | "Expr":
// | [*expr.Variable]
//| "Position": Pos{Line: 8-8 Pos: 124-127};
// | "Position": Pos{Line: 8-8 Pos: 124-127}
// | "Comments":
// | "// some comment\n" before "VariableToken"
// | "VarName":
// | [*node.Identifier]
//| "Position": Pos{Line: 8-8 Pos: 124-127};
//| "Value": var;
// | "Position": Pos{Line: 8-8 Pos: 124-127}
// | "Value": "var"
}

97
visitor/json_dumper.go Normal file
View File

@ -0,0 +1,97 @@
// Package visitor contains walker.visitor implementations
package visitor
import (
"fmt"
"io"
"reflect"
"github.com/z7zmey/php-parser/node"
"github.com/z7zmey/php-parser/parser"
"github.com/z7zmey/php-parser/walker"
)
type JsonDumper struct {
Writer io.Writer
Comments parser.Comments
Positions parser.Positions
NsResolver *NamespaceResolver
}
// 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()
fmt.Fprintf(d.Writer, "{%q:%q", "type", nodeType)
if d.Positions != nil {
if p := d.Positions[n]; p != nil {
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 d.Comments != nil {
if c := d.Comments[n]; len(c) > 0 {
fmt.Fprintf(d.Writer, ",%q:[", "comments")
for k, cc := range c {
if k == 0 {
fmt.Fprintf(d.Writer, "%q", cc)
} else {
fmt.Fprintf(d.Writer, ",%q", cc)
}
}
fmt.Fprint(d.Writer, "]")
}
}
if a := n.Attributes(); len(a) > 0 {
for key, attr := range a {
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 *JsonDumper) LeaveNode(n walker.Walkable) {
fmt.Fprint(d.Writer, "}")
}
func (d *JsonDumper) EnterChildNode(key string, w walker.Walkable) {
fmt.Fprintf(d.Writer, ",%q:", key)
}
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)
}
func (d *JsonDumper) LeaveChildList(key string, w walker.Walkable) {
fmt.Fprint(d.Writer, "]")
}

View File

@ -0,0 +1,43 @@
//Package visitor contains walker.visitor implementations
package visitor_test
import (
"bytes"
"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
$var;
}
}
}`
php7parser := php7.NewParser(bytes.NewBufferString(src), "test.php")
php7parser.Parse()
nodes := php7parser.GetRootNode()
nsResolver := visitor.NewNamespaceResolver()
nodes.Walk(nsResolver)
dumper := &visitor.JsonDumper{
Writer: os.Stdout,
Comments: php7parser.GetComments(),
Positions: php7parser.GetPositions(),
NsResolver: nsResolver,
}
nodes.Walk(dumper)
// Unordered output:
// {"type":"*node.Root","position":{"startPos":10,"endPos":166,"startLine":3,"endLine":12},"Stmts":[{"type":"*stmt.Namespace","position":{"startPos":10,"endPos":166,"startLine":3,"endLine":12},"NamespaceName":{"type":"*name.Name","position":{"startPos":20,"endPos":22,"startLine":3,"endLine":3},"Parts":[{"type":"*name.NamePart","position":{"startPos":20,"endPos":22,"startLine":3,"endLine":3},"Value":"Foo"}]},"Stmts":[{"type":"*stmt.Class","position":{"startPos":29,"endPos":162,"startLine":4,"endLine":11},"namespacedName":"Foo\\Bar","PhpDocComment":"","ClassName":{"type":"*node.Identifier","position":{"startPos":35,"endPos":37,"startLine":4,"endLine":4},"Value":"Bar"},"Stmts":[{"type":"*stmt.ClassMethod","position":{"startPos":45,"endPos":157,"startLine":5,"endLine":10},"ReturnsRef":false,"PhpDocComment":"","MethodName":{"type":"*node.Identifier","position":{"startPos":61,"endPos":72,"startLine":5,"endLine":5},"Value":"FunctionName"},"Modifiers":[{"type":"*node.Identifier","position":{"startPos":45,"endPos":50,"startLine":5,"endLine":5},"Value":"public"}],"Params":[{"type":"*node.Parameter","position":{"startPos":74,"endPos":89,"startLine":5,"endLine":5},"ByRef":false,"Variadic":false,"VariableType":{"type":"*name.Name","position":{"startPos":74,"endPos":77,"startLine":5,"endLine":5},"namespacedName":"Foo\\Type","Parts":[{"type":"*name.NamePart","position":{"startPos":74,"endPos":77,"startLine":5,"endLine":5},"Value":"Type"}]},"Variable":{"type":"*expr.Variable","position":{"startPos":79,"endPos":82,"startLine":5,"endLine":5},"VarName":{"type":"*node.Identifier","position":{"startPos":79,"endPos":82,"startLine":5,"endLine":5},"Value":"var"}},"DefaultValue":{"type":"*expr.ConstFetch","position":{"startPos":86,"endPos":89,"startLine":5,"endLine":5},"Constant":{"type":"*name.Name","position":{"startPos":86,"endPos":89,"startLine":5,"endLine":5},"namespacedName":"null","Parts":[{"type":"*name.NamePart","position":{"startPos":86,"endPos":89,"startLine":5,"endLine":5},"Value":"null"}]}}}],"Stmt":{"type":"*stmt.StmtList","position":{"startPos":96,"endPos":157,"startLine":6,"endLine":10},"Stmts":[{"type":"*stmt.Expression","position":{"startPos":147,"endPos":151,"startLine":9,"endLine":9},"Expr":{"type":"*expr.Variable","position":{"startPos":147,"endPos":150,"startLine":9,"endLine":9},"comments":["// some comment\n","// second comment\n"],"VarName":{"type":"*node.Identifier","position":{"startPos":147,"endPos":150,"startLine":9,"endLine":9},"Value":"var"}}}]}}]}]}]}
}

View File

@ -0,0 +1,145 @@
// Package visitor contains walker.visitor implementations
package visitor
import (
"fmt"
"io"
"reflect"
"github.com/z7zmey/php-parser/node"
"github.com/z7zmey/php-parser/parser"
"github.com/z7zmey/php-parser/walker"
)
type PrettyJsonDumper struct {
Writer io.Writer
Comments parser.Comments
Positions parser.Positions
NsResolver *NamespaceResolver
depth int
isChildNode bool
}
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 {
d.printIndent(d.Writer)
}
fmt.Fprint(d.Writer, "{\n")
d.depth++
d.printIndent(d.Writer)
fmt.Fprintf(d.Writer, "%q: %q", "type", nodeType)
if d.Positions != nil {
if p := d.Positions[n]; 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 d.Comments != nil {
if c := d.Comments[n]; len(c) > 0 {
fmt.Fprint(d.Writer, ",\n")
d.printIndent(d.Writer)
fmt.Fprint(d.Writer, "\"comments\": [\n")
d.depth++
for k, cc := range c {
if k == 0 {
d.printIndent(d.Writer)
fmt.Fprintf(d.Writer, "%q", cc)
} else {
fmt.Fprint(d.Writer, ",\n")
d.printIndent(d.Writer)
fmt.Fprintf(d.Writer, "%q", cc)
}
}
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++
}
func (d *PrettyJsonDumper) LeaveChildList(key string, w walker.Walkable) {
d.depth--
fmt.Fprint(d.Writer, "\n")
d.printIndent(d.Writer)
fmt.Fprint(d.Writer, "]")
}

View File

@ -0,0 +1,269 @@
//Package visitor contains walker.visitor implementations
package visitor_test
import (
"bytes"
"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;
}
}
}`
php7parser := php7.NewParser(bytes.NewBufferString(src), "test.php")
php7parser.Parse()
nodes := php7parser.GetRootNode()
nsResolver := visitor.NewNamespaceResolver()
nodes.Walk(nsResolver)
dumper := &visitor.PrettyJsonDumper{
Writer: os.Stdout,
Comments: php7parser.GetComments(),
Positions: php7parser.GetPositions(),
NsResolver: nsResolver,
}
nodes.Walk(dumper)
// Unordered output:
// {
// "type": "*node.Root",
// "position": {
// "startPos": 10,
// "endPos": 166,
// "startLine": 3,
// "endLine": 12
// },
// "Stmts": [
// {
// "type": "*stmt.Namespace",
// "position": {
// "startPos": 10,
// "endPos": 166,
// "startLine": 3,
// "endLine": 12
// },
// "NamespaceName": {
// "type": "*name.Name",
// "position": {
// "startPos": 20,
// "endPos": 22,
// "startLine": 3,
// "endLine": 3
// },
// "Parts": [
// {
// "type": "*name.NamePart",
// "position": {
// "startPos": 20,
// "endPos": 22,
// "startLine": 3,
// "endLine": 3
// },
// "Value": "Foo"
// }
// ]
// },
// "Stmts": [
// {
// "type": "*stmt.Class",
// "position": {
// "startPos": 29,
// "endPos": 162,
// "startLine": 4,
// "endLine": 11
// },
// "namespacedName": "Foo\\Bar",
// "PhpDocComment": "",
// "ClassName": {
// "type": "*node.Identifier",
// "position": {
// "startPos": 35,
// "endPos": 37,
// "startLine": 4,
// "endLine": 4
// },
// "Value": "Bar"
// },
// "Stmts": [
// {
// "type": "*stmt.ClassMethod",
// "position": {
// "startPos": 45,
// "endPos": 157,
// "startLine": 5,
// "endLine": 10
// },
// "ReturnsRef": false,
// "PhpDocComment": "",
// "MethodName": {
// "type": "*node.Identifier",
// "position": {
// "startPos": 61,
// "endPos": 72,
// "startLine": 5,
// "endLine": 5
// },
// "Value": "FunctionName"
// },
// "Modifiers": [
// {
// "type": "*node.Identifier",
// "position": {
// "startPos": 45,
// "endPos": 50,
// "startLine": 5,
// "endLine": 5
// },
// "Value": "public"
// }
// ],
// "Params": [
// {
// "type": "*node.Parameter",
// "position": {
// "startPos": 74,
// "endPos": 89,
// "startLine": 5,
// "endLine": 5
// },
// "ByRef": false,
// "Variadic": false,
// "VariableType": {
// "type": "*name.Name",
// "position": {
// "startPos": 74,
// "endPos": 77,
// "startLine": 5,
// "endLine": 5
// },
// "namespacedName": "Foo\\Type",
// "Parts": [
// {
// "type": "*name.NamePart",
// "position": {
// "startPos": 74,
// "endPos": 77,
// "startLine": 5,
// "endLine": 5
// },
// "Value": "Type"
// }
// ]
// },
// "Variable": {
// "type": "*expr.Variable",
// "position": {
// "startPos": 79,
// "endPos": 82,
// "startLine": 5,
// "endLine": 5
// },
// "VarName": {
// "type": "*node.Identifier",
// "position": {
// "startPos": 79,
// "endPos": 82,
// "startLine": 5,
// "endLine": 5
// },
// "Value": "var"
// }
// },
// "DefaultValue": {
// "type": "*expr.ConstFetch",
// "position": {
// "startPos": 86,
// "endPos": 89,
// "startLine": 5,
// "endLine": 5
// },
// "Constant": {
// "type": "*name.Name",
// "position": {
// "startPos": 86,
// "endPos": 89,
// "startLine": 5,
// "endLine": 5
// },
// "namespacedName": "null",
// "Parts": [
// {
// "type": "*name.NamePart",
// "position": {
// "startPos": 86,
// "endPos": 89,
// "startLine": 5,
// "endLine": 5
// },
// "Value": "null"
// }
// ]
// }
// }
// }
// ],
// "Stmt": {
// "type": "*stmt.StmtList",
// "position": {
// "startPos": 96,
// "endPos": 157,
// "startLine": 6,
// "endLine": 10
// },
// "Stmts": [
// {
// "type": "*stmt.Expression",
// "position": {
// "startPos": 147,
// "endPos": 151,
// "startLine": 9,
// "endLine": 9
// },
// "Expr": {
// "type": "*expr.Variable",
// "position": {
// "startPos": 147,
// "endPos": 150,
// "startLine": 9,
// "endLine": 9
// },
// "comments": [
// "// some comment\n",
// "// second comment\n"
// ],
// "VarName": {
// "type": "*node.Identifier",
// "position": {
// "startPos": 147,
// "endPos": 150,
// "startLine": 9,
// "endLine": 9
// },
// "Value": "var"
// }
// }
// }
// ]
// }
// }
// ]
// }
// ]
// }
// ]
// }
}