Babelfish Go client library provides functionality to both connecting to the Babelfish server for parsing code (obtaining an UAST as a result) and for analysing UASTs with the functionality provided by libuast.
The recommended way to install go-client is:
go get -u github.com/bblfsh/go-client/v4/...
Although go-client is a library, this codebase also includes an example of bblfsh-cli
application at ./cmd/bblfsh-cli
. When installed, it allows to parse a single file, query it with XPath and print the resulting UAST structure immediately.
See $ bblfsh-cli -h
for list of all available CLI options.
This small example illustrates how to retrieve the UAST from a small Python script.
If you don't have a bblfsh server installed, please read the getting started guide, to learn more about how to use and deploy a bblfsh server.
Go to the quick start to discover how to run Babelfish with Docker.
package main
import (
"context"
"fmt"
"time"
"github.com/bblfsh/go-client/v4"
"github.com/bblfsh/go-client/v4/tools"
"github.com/bblfsh/sdk/v3/uast/nodes"
"github.com/bblfsh/sdk/v3/uast/uastyaml"
"google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
)
func main() {
ctx := context.Background()
client, err := bblfsh.NewClientContext(ctx, "0.0.0.0:9432",
// Set an extra grpc DialOptions to avoid "transport closing" errors when client is idle.
// Passing keepalive params here, you can overwrite defaults:
// Time: 2 minutes, PermitWithoutStream: true
grpc.WithKeepaliveParams(keepalive.ClientParameters{
// Time is a duration after this if the client doesn't see any activity it
// pings the server to see if the transport is still alive.
Time: 2 * time.Minute,
// PermitWithoutStream is a boolean flag.
// If true, client sends keepalive pings even with no active RPCs.
PermitWithoutStream: true,
}),
)
if err != nil {
panic(err)
}
python := "import foo"
res, _, err := client.NewParseRequest().Context(ctx).
Language("python").Content(python).UAST()
if err != nil {
panic(err)
}
query := "//*[self::uast:Import or self::uast:RuntimeImport]"
it, _ := tools.Filter(res, query)
var nodeAr nodes.Array
for it.Next() {
nodeAr = append(nodeAr, it.Node().(nodes.Node))
}
// The example below emits YAML.
//
// Alternative 1: encode UAST nodes to JSON.
// data, err := json.MarshalIndent(nodeAr, "", " ")
//
// Alternative 2: encode UAST nodes to protobuf.
// import "github.com/bblfsh/sdk/v3/uast/nodes/nodesproto"
// ...
// for _, node := range nodesAr {
// err := nodesproto.WriteTo(os.Stdout, nodeAr) // check
// ...
// }
//
data, err := uastyaml.Marshal(nodeAr)
if err != nil {
panic(err)
}
fmt.Println(string(data))
}
produces
{ '@type': "uast:RuntimeImport",
'@pos': { '@type': "uast:Positions",
start: { '@type': "uast:Position",
offset: 0,
line: 1,
col: 1,
},
},
All: false,
Names: ~,
Path: { '@type': "uast:Identifier",
'@pos': { '@type': "uast:Positions",
},
Name: "foo",
},
Target: ~,
},
]
iter := tools.NewIterator(res, tools.PreOrder)
for node := range tools.Iterate(iter) {
fmt.Println(node)
}
// For XPath expressions returning a boolean/numeric/string value, you must
// use the right typed Filter function:
boolres, err := tools.FilterBool(res, "boolean(//*[@start-offset or @end-offset])")
strres, err := tools.FilterString(res, "name(//*[1])")
numres, err := tools.FilterNumber(res, "count(//*)")
Please read the Babelfish clients guide section to learn more about babelfish clients and their query language.
Apache License 2.0, see LICENSE