Files
moxa/interp/dot.go
Marc Vertes 151699ef9f feature: test subcommand to run test and benchmark functions
This change allows the interpreter to execute tests and benchmarks
functions provided by packages.

The test subcommand is similar to the "go test" command and
all the relevant flags have been kept.

The ability to evaluate a directory or a package has also been added.

A new method Symbol to access exported symbol values of an interpreted
package has been added. This method is used by the test subcommand.

An EvalTest method has been added to evaluate all Go files, including "*_test.go".

The testing packages from the standard library have been added to stdlib used
symbols.
2020-09-14 11:14:04 +02:00

96 lines
2.3 KiB
Go

package interp
import (
"fmt"
"io"
"io/ioutil"
"log"
"os/exec"
"path/filepath"
"strings"
)
// astDot displays an AST in graphviz dot(1) format using dotty(1) co-process.
func (n *node) astDot(out io.Writer, name string) {
fmt.Fprintf(out, "digraph ast {\n")
fmt.Fprintf(out, "labelloc=\"t\"\n")
fmt.Fprintf(out, "label=\"%s\"\n", name)
n.Walk(func(n *node) bool {
var label string
switch n.kind {
case basicLit, identExpr:
label = strings.ReplaceAll(n.ident, "\"", "\\\"")
default:
if n.action != aNop {
label = n.action.String()
} else {
label = n.kind.String()
}
}
fmt.Fprintf(out, "%d [label=\"%d: %s\"]\n", n.index, n.index, label)
if n.anc != nil {
fmt.Fprintf(out, "%d -> %d\n", n.anc.index, n.index)
}
return true
}, nil)
fmt.Fprintf(out, "}\n")
}
// cfgDot displays a CFG in graphviz dot(1) format using dotty(1) co-process.
func (n *node) cfgDot(out io.Writer) {
fmt.Fprintf(out, "digraph cfg {\n")
n.Walk(nil, func(n *node) {
if n.kind == basicLit || n.tnext == nil {
return
}
var label string
if n.action == aNop {
label = "nop: end_" + n.kind.String()
} else {
label = n.action.String()
}
fmt.Fprintf(out, "%d [label=\"%d: %v %d\"]\n", n.index, n.index, label, n.findex)
if n.fnext != nil {
fmt.Fprintf(out, "%d -> %d [color=green]\n", n.index, n.tnext.index)
fmt.Fprintf(out, "%d -> %d [color=red]\n", n.index, n.fnext.index)
} else if n.tnext != nil {
fmt.Fprintf(out, "%d -> %d\n", n.index, n.tnext.index)
}
})
fmt.Fprintf(out, "}\n")
}
type nopCloser struct {
io.Writer
}
func (nopCloser) Close() error { return nil }
// dotWriter returns an output stream to a dot(1) co-process where to write data in .dot format.
func dotWriter(dotCmd string) io.WriteCloser {
if dotCmd == "" {
return nopCloser{ioutil.Discard}
}
fields := strings.Fields(dotCmd)
cmd := exec.Command(fields[0], fields[1:]...)
dotin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
if err = cmd.Start(); err != nil {
log.Fatal(err)
}
return dotin
}
func defaultDotCmd(filePath, prefix string) string {
dir, fileName := filepath.Split(filePath)
ext := filepath.Ext(fileName)
if ext == "" {
fileName += ".dot"
} else {
fileName = strings.Replace(fileName, ext, ".dot", 1)
}
return "dot -Tdot -o" + dir + prefix + fileName
}