summaryrefslogtreecommitdiff
path: root/debug
diff options
context:
space:
mode:
Diffstat (limited to 'debug')
-rw-r--r--debug/frames.go66
-rw-r--r--debug/frames_test.go24
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])
+ })
+ }
+}