Pages

Saturday, October 11, 2014

How to Write Hello World in Go (in Go)

Let's write "hello world" in go.

Sure, you can do it this way:

package main

import "fmt"

func main() {
fmt.Printf("Hello world.\n")
}

But that's no fun, is it?
"Give a clever engineer a straightforward problem and they'll add complexity until it's interesting enough to solve."
Let's write a program that writes hello.go for us!  That's right: write go, using go.

(Sure, you could just write a program that echos the above source text as a quoted string to stdout, but that's not much fun. We must add more complexity to make it interesting.)

The "go/ast" package is used by gofmt and gofix (and various other tools) to parse and manipulate go source code in the form of abstract syntax trees.

We're going to build a new go program from scratch, in go, so we're not really interested in parsing so much as constructing an AST and printing the result as human-readable source code.

Here's a skeleton that uses go/ast to construct an AST for a very minimal go program that compiles, but doesn't actually do anything:

package main

import (
"bytes"
"fmt"
"go/ast"
"go/printer"
"go/token"
)

func main() {
// Start with a file
f := &ast.File{
Name: &ast.Ident{
// The package name is "main"
Name: "main",
},
// Top-level declarations in this file:
Decls: []ast.Decl{
// A basic func declaration with no receiver:
&ast.FuncDecl{
Name: &ast.Ident{
// This func is named "main"
Name: "main",
},
// With an empty func type (no params, no returns)
Type: &ast.FuncType{},
// And an empty body.
Body: &ast.BlockStmt{},
},
},
}

fset := token.NewFileSet()

var buf bytes.Buffer
printer.Fprint(&buf, fset, f)
fmt.Printf("%s\n", buf.String())
}

Try it out on play.golang.org here.  It produces the following:

package main

func main() {
}

Which does compile, but doesn't actually do anything.  Let's add the next pieces: The import statement for "fmt" and the fmt.Printf statement that actually prints "Hello world."

To add the import statement, add a new element to f.Decls:

// Start an "import" declaration
&ast.GenDecl{
Tok: token.IMPORT,
Specs: []ast.Spec{
&ast.ImportSpec{
// With a string literal of "fmt"
Path: &ast.BasicLit{
Kind:  token.STRING,
// Note the "" contained in ``
Value: `"fmt"`,
},
},
},
},

If you leave f.Decls as it is here and run it, it will produce the following:

package main

import "fmt"

func main() {
}

Which will fail to compile because "fmt" is unused.  So let's use it by adding the fmt.Printf statement inside the body of main(). Change the empty Body: &ast.BlockStmt{} in the above skeleton to include some ast.Stmts:

Body: &ast.BlockStmt{
List: []ast.Stmt{
// Start a stand-alone expression statement
&ast.ExprStmt{
// Representing a function call to "fmt"
X: &ast.CallExpr{
Fun: &ast.SelectorExpr{
X: &ast.Ident{
Name: "fmt",
},
// With a selector for Printf
Sel: &ast.Ident{
Name: "Printf",
},
},
// And a single-element arg list consisting of a string literal
Args: []ast.Expr{
&ast.BasicLit{
Kind:  token.STRING,
Value: `"Hello world.\n"`,
},
},
},
},
},
},

This will finally produce a runnable hello world:

package main

import "fmt"

func main() {
fmt.Printf("Hello world.\n")
}

Try the final product out on play.golang.org here.

In conclusion, if you'd like to do some code generation with go, this might not be a bad place to start. You can explore other parts of go/ast by adding some extra function declarations with actual parameter lists, return values and even receiver types, and then calling them from main.

If I was really bored, I'd write a further iteration of this program that constructs itself :)


9 comments:

  1. Thank you for your post. This was really an appreciating one. You done a good job. Keep on blogging like this unique information with us.


    Web Designing Training in Chennai

    ReplyDelete
  2. Wow amazing i saw the article with execution models you had posted. It was such informative. Really its a wonderful article. Thank you for sharing and please keep update like this type of article because i want to learn more relevant to this topic.

    SEO Company in Chennai

    ReplyDelete
  3. you had to share this style content is fantastic info for me.I'm read find that some content line very interesting.
    Hadoop Course in Chennai
    Hadoop Training in Chennai
    Informatica Training

    ReplyDelete