#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. Dump AST to stdout.
Example Example

57
main.go
View File

@ -17,11 +17,18 @@ import (
var wg sync.WaitGroup var wg sync.WaitGroup
var usePhp5 *bool var usePhp5 *bool
var noDump *bool var dumpType string
var showPositions *bool
var showComments *bool
var showResolvedNs *bool
func main() { func main() {
usePhp5 = flag.Bool("php5", false, "use PHP5 parserWorker") usePhp5 = flag.Bool("php5", false, "parse as PHP5")
noDump = flag.Bool("noDump", false, "disable dumping to stdout") 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() flag.Parse()
pathCh := make(chan string) pathCh := make(chan string)
@ -95,19 +102,53 @@ func printer(result <-chan parser.Parser) {
fmt.Println(e) fmt.Println(e)
} }
if !*noDump { var nsResolver *visitor.NamespaceResolver
nsResolver := visitor.NewNamespaceResolver() if *showResolvedNs {
nsResolver = visitor.NewNamespaceResolver()
parserWorker.GetRootNode().Walk(nsResolver) 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{ dumper := &visitor.Dumper{
Writer: os.Stdout, Writer: os.Stdout,
Indent: " | ", Indent: "| ",
Comments: parserWorker.GetComments(), Comments: comments,
Positions: parserWorker.GetPositions(), Positions: positions,
NsResolver: nsResolver, NsResolver: nsResolver,
} }
parserWorker.GetRootNode().Walk(dumper) 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() wg.Done()
} }
} }

View File

@ -32,13 +32,13 @@ func (d *Dumper) EnterNode(w walker.Walkable) bool {
if d.Positions != nil { if d.Positions != nil {
if p := d.Positions[n]; p != 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 d.NsResolver != nil {
if namespacedName, ok := d.NsResolver.ResolvedNames[n]; ok { 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 { if a := n.Attributes(); len(a) > 0 {
for key, attr := range a { 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

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