// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package ssa import ( "bytes" "fmt" "html" "io" "os" ) type HTMLWriter struct { Logger *os.File } func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter { out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { logger.Fatalf(0, "%v", err) } html := HTMLWriter{File: out, Logger: logger} html.start(funcname) return &html } func (w *HTMLWriter) start(name string) { if w == nil { return } w.WriteString("") w.WriteString(` `) // TODO: Add javascript click handlers for blocks // to outline that block across all phases w.WriteString("") w.WriteString("

") w.WriteString(html.EscapeString(name)) w.WriteString("

") w.WriteString(` help

Click on a value or block to toggle highlighting of that value/block and its uses. Values and blocks are highlighted by ID, which may vary across passes. (TODO: Fix this.)

Faded out values and blocks are dead code that has not been eliminated.

Values printed in italics have a dependency cycle.

`) w.WriteString("") w.WriteString("") } func (w *HTMLWriter) Close() { if w == nil { return } w.WriteString("") w.WriteString("
") w.WriteString("") w.WriteString("") w.File.Close() } // WriteFunc writes f in a column headed by title. func (w *HTMLWriter) WriteFunc(title string, f *Func) { if w == nil { return // avoid generating HTML just to discard it } w.WriteColumn(title, f.HTML()) // TODO: Add visual representation of f's CFG. } // WriteColumn writes raw HTML in a column headed by title. // It is intended for pre- and post-compilation log output. func (w *HTMLWriter) WriteColumn(title string, html string) { if w == nil { return } w.WriteString("") w.WriteString("

" + title + "

") w.WriteString(html) w.WriteString("") } func (w *HTMLWriter) Printf(msg string, v ...interface{}) { if _, err := fmt.Fprintf(w.File, msg, v...); err != nil { w.Fatalf(0, "%v", err) } } func (w *HTMLWriter) WriteString(s string) { if _, err := w.File.WriteString(s); err != nil { w.Fatalf(0, "%v", err) } } func (v *Value) HTML() string { // TODO: Using the value ID as the class ignores the fact // that value IDs get recycled and that some values // are transmuted into other values. return fmt.Sprintf("%[1]s", v.String()) } func (v *Value) LongHTML() string { // TODO: Any intra-value formatting? // I'm wary of adding too much visual noise, // but a little bit might be valuable. // We already have visual noise in the form of punctuation // maybe we could replace some of that with formatting. s := fmt.Sprintf("", v.String()) s += fmt.Sprintf("%s = %s", v.HTML(), v.Op.String()) s += " <" + html.EscapeString(v.Type.String()) + ">" s += html.EscapeString(v.auxString()) for _, a := range v.Args { s += fmt.Sprintf(" %s", a.HTML()) } r := v.Block.Func.RegAlloc if int(v.ID) < len(r) && r[v.ID] != nil { s += " : " + html.EscapeString(r[v.ID].Name()) } s += "" return s } func (b *Block) HTML() string { // TODO: Using the value ID as the class ignores the fact // that value IDs get recycled and that some values // are transmuted into other values. return fmt.Sprintf("%[1]s", html.EscapeString(b.String())) } func (b *Block) LongHTML() string { // TODO: improve this for HTML? s := fmt.Sprintf("%s", html.EscapeString(b.String()), html.EscapeString(b.Kind.String())) if b.Aux != nil { s += html.EscapeString(fmt.Sprintf(" {%v}", b.Aux)) } if b.Control != nil { s += fmt.Sprintf(" %s", b.Control.HTML()) } if len(b.Succs) > 0 { s += " →" // right arrow for _, e := range b.Succs { c := e.b s += " " + c.HTML() } } switch b.Likely { case BranchUnlikely: s += " (unlikely)" case BranchLikely: s += " (likely)" } return s } func (f *Func) HTML() string { var buf bytes.Buffer fmt.Fprint(&buf, "") p := htmlFuncPrinter{w: &buf} fprintFunc(p, f) // fprintFunc(&buf, f) // TODO: HTML, not text,
for line breaks, etc. fmt.Fprint(&buf, "
") return buf.String() } type htmlFuncPrinter struct { w io.Writer } func (p htmlFuncPrinter) header(f *Func) {} func (p htmlFuncPrinter) startBlock(b *Block, reachable bool) { // TODO: Make blocks collapsable? var dead string if !reachable { dead = "dead-block" } fmt.Fprintf(p.w, "") // io.WriteString(p.w, "") } func (p htmlFuncPrinter) value(v *Value, live bool) { var dead string if !live { dead = "dead-value" } fmt.Fprintf(p.w, "
  • ", dead) fmt.Fprint(p.w, v.LongHTML()) io.WriteString(p.w, "
  • ") } func (p htmlFuncPrinter) startDepCycle() { fmt.Fprintln(p.w, "") } func (p htmlFuncPrinter) endDepCycle() { fmt.Fprintln(p.w, "") } func (p htmlFuncPrinter) named(n LocalSlot, vals []*Value) { // TODO }