diff options
Diffstat (limited to 'debug')
-rw-r--r-- | debug/frames.go | 66 | ||||
-rw-r--r-- | debug/frames_test.go | 24 |
2 files changed, 90 insertions, 0 deletions
diff --git a/debug/frames.go b/debug/frames.go new file mode 100644 index 0000000..88a48f0 --- /dev/null +++ b/debug/frames.go @@ -0,0 +1,66 @@ +package debug + +import ( + "bufio" + "fmt" + "os" + "path/filepath" + "regexp" + "runtime" + "strings" +) + +var varRegex = regexp.MustCompile(`(?:var)?\s*(\w*)\s*:?=`) + +func getPackageName(f runtime.Frame) string { + parts := strings.Split(f.Func.Name(), ".") + pl := len(parts) + + if parts[pl-2][0] == '(' { + return strings.Join(parts[0:pl-2], ".") + } else { + return strings.Join(parts[0:pl-1], ".") + } +} + +func getVarName(filename string, lineNo int) string { + f, err := os.Open(filename) + if err != nil { + return "" + } + + scanner := bufio.NewScanner(f) + for i := 0; i < lineNo; i++ { + scanner.Scan() + } + + line := scanner.Text() + if matches := varRegex.FindStringSubmatch(line); matches != nil { + return matches[1] + } + return "" +} + +// GetDefinition returns the name of the variable and location this parser was defined by walking up the stack +func GetDefinition() (varName string, location string) { + pc := make([]uintptr, 64) + n := runtime.Callers(3, pc) + frames := runtime.CallersFrames(pc[:n]) + + var frame runtime.Frame + more := true + for more { + frame, more = frames.Next() + pkg := getPackageName(frame) + if pkg == "github.com/vektah/goparsify" || pkg == "github.com/vektah/goparsify/debug" { + continue + } + + varName := getVarName(frame.File, frame.Line) + if varName != "" { + return varName, fmt.Sprintf("%s:%d", filepath.Base(frame.File), frame.Line) + } + } + + return "", "" +} diff --git a/debug/frames_test.go b/debug/frames_test.go new file mode 100644 index 0000000..40c1086 --- /dev/null +++ b/debug/frames_test.go @@ -0,0 +1,24 @@ +package debug + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestRegex(t *testing.T) { + tests := map[string]string{ + "attrs": ` attrs = Map(Some(attr), func(node Result) Result {`, + "_value": ` _value = Any(_null, _true, _false, _string, _number, _array, _object)`, + "_object": `_object = Map(Seq("{", Cut, _properties, "}"), func(n Result) Result {`, + "expr": `var expr = Exact("foo")`, + "number": `number := NumberLit()`, + } + for expected, input := range tests { + t.Run(input, func(t *testing.T) { + matches := varRegex.FindStringSubmatch(input) + require.NotNil(t, matches) + require.Equal(t, expected, matches[1]) + }) + } +} |