├── .godir ├── .screenshot.png ├── LICENSE ├── Procfile ├── README.md ├── index.html └── ssaview.go /.godir: -------------------------------------------------------------------------------- 1 | ssaview 2 | -------------------------------------------------------------------------------- /.screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmc/ssaview/bd678c564ecb1feb8d5d0224f02d1b2bbe40825b/.screenshot.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Travis Cline 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose 4 | with or without fee is hereby granted, provided that the above copyright notice 5 | and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 9 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 11 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 12 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 13 | THIS SOFTWARE. 14 | 15 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: ssaview 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ssaview 2 | ------- 3 | http://golang-ssaview.herokuapp.com/ 4 | 5 | ssaview is a small utlity that renders SSA code alongside input Go code 6 | 7 | Runs via HTTP on :8080 8 | 9 | License: ISC 10 | 11 | ```sh 12 | $ go get github.com/tmc/ssaview 13 | $ ssaview & 14 | $ open http://localhost:8080/ 15 | ``` 16 | 17 | Ideas for extension: 18 | 19 | - [ ] proper fullscreen ui 20 | - [ ] allow selection in one editor to highlight the associated code in the other 21 | - [ ] include interpreter 22 | 23 | Deploying: 24 | 25 | On Heroku: Uses custom buildpack to preserve GOROOT: 26 | 27 | ```sh 28 | $ heroku buildpacks:set https://github.com/tmc/heroku-buildpack-go.gi 29 | ``` 30 | 31 | Screenshot: 32 | ![Example screenshot](https://github.com/tmc/ssaview/raw/master/.screenshot.png) 33 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Go SSA viewer

13 |

https://github.com/tmc/ssaview

14 |

Shows the SSA (Static Single Assignment) representation of input code.
Uses the wonderful golang.org/x/tools/go/ssa package.

15 |
16 |
17 |
18 |
19 | 20 | status:
21 |
22 |
23 |
24 | Input 25 |
 26 | package main
 27 | 
 28 | import "fmt"
 29 | 
 30 | func main() {
 31 | 	a, b := 42, 43
 32 | 	equal(a, b)
 33 | 	fmt.Println("Let's see the SSA representation of this program")
 34 | }
 35 | 
 36 | func equal(i, j int) bool {
 37 | 	// needless closure
 38 | 	inner := func() bool {
 39 | 		return i == j
 40 | 	}
 41 | 	return inner()
 42 | }
43 |
44 |
45 |
46 | Result 47 |

 48 | 	
49 |
50 |
51 | 52 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ssaview.go: -------------------------------------------------------------------------------- 1 | // ssaview is a small utlity that renders SSA code alongside input Go code 2 | // 3 | // Runs via HTTP on :8080 or the PORT environment variable 4 | package main 5 | 6 | import ( 7 | "bytes" 8 | "encoding/json" 9 | "fmt" 10 | "go/build" 11 | "go/token" 12 | "io" 13 | "net/http" 14 | "os" 15 | "sort" 16 | 17 | "golang.org/x/tools/go/loader" 18 | "golang.org/x/tools/go/ssa" 19 | "golang.org/x/tools/go/ssa/ssautil" 20 | ) 21 | 22 | const indexPage = "index.html" 23 | 24 | type members []ssa.Member 25 | 26 | func (m members) Len() int { return len(m) } 27 | func (m members) Swap(i, j int) { m[i], m[j] = m[j], m[i] } 28 | func (m members) Less(i, j int) bool { return m[i].Pos() < m[j].Pos() } 29 | 30 | // toSSA converts go source to SSA 31 | func toSSA(source io.Reader, fileName, packageName string, debug bool) ([]byte, error) { 32 | // adopted from saa package example 33 | 34 | conf := loader.Config{ 35 | Build: &build.Default, 36 | } 37 | 38 | file, err := conf.ParseFile(fileName, source) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | conf.CreateFromFiles("main.go", file) 44 | 45 | prog, err := conf.Load() 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | ssaProg := ssautil.CreateProgram(prog, ssa.NaiveForm|ssa.BuildSerially) 51 | ssaProg.Build() 52 | mainPkg := ssaProg.Package(prog.InitialPackages()[0].Pkg) 53 | 54 | out := new(bytes.Buffer) 55 | mainPkg.SetDebugMode(debug) 56 | mainPkg.WriteTo(out) 57 | mainPkg.Build() 58 | 59 | // grab just the functions 60 | funcs := members([]ssa.Member{}) 61 | for _, obj := range mainPkg.Members { 62 | if obj.Token() == token.FUNC { 63 | funcs = append(funcs, obj) 64 | } 65 | } 66 | // sort by Pos() 67 | sort.Sort(funcs) 68 | for _, f := range funcs { 69 | mainPkg.Func(f.Name()).WriteTo(out) 70 | } 71 | return out.Bytes(), nil 72 | } 73 | 74 | // writeJSON attempts to serialize data and write it to w 75 | // On error it will write an HTTP status of 400 76 | func writeJSON(w http.ResponseWriter, data interface{}) error { 77 | if err, ok := data.(error); ok { 78 | data = struct{ Error string }{err.Error()} 79 | w.WriteHeader(400) 80 | } 81 | o, err := json.MarshalIndent(data, "", " ") 82 | if err != nil { 83 | return err 84 | } 85 | _, err = w.Write(o) 86 | return err 87 | } 88 | 89 | func main() { 90 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 91 | f, err := os.Open(indexPage) 92 | if err != nil { 93 | writeJSON(w, err) 94 | } 95 | io.Copy(w, f) 96 | }) 97 | http.HandleFunc("/ssa", func(w http.ResponseWriter, r *http.Request) { 98 | ssa, err := toSSA(r.Body, "main.go", "main", false) 99 | if err != nil { 100 | writeJSON(w, err) 101 | return 102 | } 103 | defer r.Body.Close() 104 | writeJSON(w, struct{ All string }{string(ssa)}) 105 | }) 106 | port := os.Getenv("PORT") 107 | if port == "" { 108 | port = "8080" 109 | } 110 | fmt.Println(http.ListenAndServe(":"+port, nil)) 111 | } 112 | --------------------------------------------------------------------------------