Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Latest commit

 

History

History
228 lines (186 loc) · 7.29 KB

grpc-usage-example.md

File metadata and controls

228 lines (186 loc) · 7.29 KB

gRPC usage example

On the previous section we checked the format of the messages exchanged using the gRPC protocol. Here, we're going to put that knowledge into practice with a simple example usage of the Babelfish server using that protocol.

This example is done in Go but you could use the gRPC interface using any programming language that supports this protocol.

Getting and compiling the .proto file

The first step involving gRPC communication is getting the .proto file that defines the types involved in the communication. The .proto format defines the structures and methods used for protocol buffer data. In the case of the Babelfish server protocol, you need to get this .proto file from the SDK. Then you have to compile it to a source file with the required structures and methods. How you generate this module is language-dependent but usually it involves installing gRPC using your language package management tool (if it has a package for it) and then use one of the provided tools.

For this example, we'll use the GogoProtobuf implementation for the Go language. This provides the protoc-gen-gogo .proto compiler so we'll use it to generate the .go interface module:

$ protoc-gen-gogo --go_out=. generated.proto

This will create a generated.pb.go file that we could then directly import into out Go code. Since the SDK is also written in Go, you could skip this step and import the modules with the already generated serializers in the Babelfish's SDK.

Making requests

Now we'll write a simple program that sends a request to get UAST of a simple "hello world" Python code that we'll provide.

package main

import (
    "context"
    "fmt"
    "os"
    "time"

    "gopkg.in/bblfsh/sdk.v2/protocol"
    "gopkg.in/bblfsh/sdk.v2/uast"
    "google.golang.org/grpc"
)

func main() {
    // Connect to the running server
    conn, err := grpc.Dial("0.0.0.0:9432", grpc.WithTimeout(time.Second*2),
        grpc.WithInsecure())
    if err != nil {
        os.Exit(1)
    }
    client := protocol.NewProtocolServiceClient(conn)
    req := &protocol.ParseRequest{
        Filename: "hello.py",
        Content:  "print('hello world!')",
        Language: "python"}
}

Now that we've created a request, we need to send it (previous code omitted):

    resp, err := client.Parse(context.TODO(), req)

Reading and interpreting the response

The code in the previous section returned a ParseResponse object that will have the format of the ParseResponse as seen on the server protocol page. You should check the status (Status in the case of Go, since public members start with uppercase); only a value of protocol.Status.OK will indicate success.

The most important member of the ParseResponse object is undoubtedly uast (UAST in Go). This will contain a Node object with the structure detailed in the previous page. This first node returned would be the root node of the UAST, and you typically would iterate over the children nodes (contained in the aptly named children field) typically using a visitor and reading the tokens and roles in the tree to do your tool.

For demonstration purposes, we'll just write a simple function that iterates the tree in preorder and print the node tokens:

func printTokens(n *uast.Node) {
    fmt.Println(n.Token)

    for _, c := range(n.Children) {
        printTokens(c)
    }
}

Now we only need to call this function on the root node in the resp variable:

   // back to main
   printTokens(resp.UAST)

Full source of the example

package main

import (
    "context"
    "fmt"
    "os"
    "strings"
    "time"

    "gopkg.in/bblfsh/sdk.v2/protocol"
    "gopkg.in/bblfsh/sdk.v2/uast"
    "google.golang.org/grpc"
)

func main() {
    // Connect to the running server
    conn, err := grpc.Dial("0.0.0.0:9432", grpc.WithTimeout(time.Second*2),
        grpc.WithInsecure())
    if err != nil {
        os.Exit(1)
    }

    client := protocol.NewProtocolServiceClient(conn)
    req := &protocol.ParseRequest{
        Filename: "hello.py",
        Content:  "print('hello world!')",
        Language: "python"}

    resp, err := client.Parse(context.TODO(), req)
    if err != nil {
        os.Exit(1)
    }

    if resp.Status != protocol.Ok {
        fmt.Println("Parsing errors:", strings.Join(resp.Errors, ", "))
        os.Exit(1)
    }

    printTokens(resp.UAST)
}

func printTokens(n *uast.Node) {
    fmt.Println(n.Token)

    for _, c := range n.Children {
        printTokens(c)
    }
}

Supported Languages

Protocol v2 and higher include a SupportedLanguages method that permits the client to discover what languages the bblfshd currently supports. The SupportedLanguagesResponse returns a list of driver manifests, giving the names and aliases of the languages each driver understands, along with version, development status, and feature support tags (see the Manifest type).

This method is supported by SDK versions ≥ 3.1.0.

Example (json):

[
    {
        "name": "C++",
        "language": "cpp",
        "aliases": [
            "C++",
            "C",
            "CUDA",
            "OpenCL",
            "Metal"
        ],
        "version": {
            "version": "v1.4.0",
            "build": {
                "seconds": 1559053620
            }
        },
        "status": "DEV_BETA",
        "features": [
            "ast",
            "uast",
            "roles"
        ]
    },
    {
        "name": "Java",
        "language": "java",
        "version": {
            "version": "v2.7.2",
            "build": {
                "seconds": 1559055732
            }
        },
        "status": "DEV_BETA",
        "features": [
            "ast",
            "uast",
            "roles"
        ]
    },
    {
        "name": "JavaScript",
        "language": "javascript",
        "aliases": [
            "JS",
            "JSX"
        ],
        "version": {
            "version": "v2.9.0",
            "build": {
                "seconds": 1559054418
            }
        },
        "status": "DEV_BETA",
        "features": [
            "ast",
            "uast",
            "roles"
        ]
    }
]

Server Version

ServerVersion method permits the client to discover what version of bblfsh server is running. The VersionResponse returns the Version object.

This method is supported by SDK versions ≥ 3.1.0.

Example (json):

{
    "version": "v2.14.0",
    "build": {
        "seconds": 1559059237
    }
}