package schema import ( "fmt" "os" "os/exec" "strings" "testing" "unsafe" gv "github.com/dominikbraun/graph" "github.com/dominikbraun/graph/draw" ) func TestParse(t *testing.T) { in := "()" + "(test)" + "(test a)" + "(test a b)" + "(test a b c)" + "(test (a b c))" + "(test (a b c d))" + "(\"hello world\")" + "(concat \"hello\" \"world\")" + "(+ 1 2)" want := "( )\n" + "(test )\n" + "(test [n'a'] )\n" + "(test [n'a'] [n'b'])\n" + "(. [n'test'] (. [n'a'] (. [n'b'] [n'c'])))\n" + "(test (a [n'b'] [n'c']) )\n" + "(test (. [n'a'] (. [n'b'] (. [n'c'] [n'd']))) )\n" + "[l'hello world']\n" + "(concat [l'hello'] [l'world'])\n" + "(+ [l1] [l2])\n" tokens, err := Tokenize([]byte(in)) if err != nil { t.Fatal(err) } parse, err := Parse(tokens) if err != nil { t.Fatal(err) } test := strings.Builder{} for _, line := range parse { test.Write([]byte(fmt.Sprintf("%s\n", line))) } if test.String() != want { t.Errorf("\ngot:\n%s\nwant:\n%s", test.String(), want) } if os.Getenv("AZALEA_TEST_VISUALIZE") == "1" { Visualize(parse) } } func hash(n *Node) uintptr { return uintptr(unsafe.Pointer(n)) } func Visualize(nodes []*Node) { g := gv.New(hash, gv.Tree(), gv.Directed()) for _, node := range nodes { addNode(node, g) } dot, _ := os.CreateTemp("", "azalea-graph-*.gv") _ = draw.DOT(g, dot) _ = exec.Command("dot", "-Tsvg", "-O", dot.Name()).Run() _ = exec.Command("qimgv", dot.Name()+".svg").Run() _ = os.Remove(dot.Name()) _ = os.Remove(dot.Name() + ".svg") } func addNode(node *Node, g gv.Graph[uintptr, *Node]) *Node { str := "" if node.Function != "" { str = node.Function } else { if node.Token != nil { str = node.Token.String() } else { return nil } } _ = g.AddVertex(node, gv.VertexAttribute("label", str)) if node.Left != nil { left := addNode(node.Left, g) _ = g.AddEdge(hash(node), hash(left), gv.EdgeAttribute("splines", "line")) } if node.Right != nil { right := addNode(node.Right, g) _ = g.AddEdge(hash(node), hash(right), gv.EdgeAttribute("splines", "line")) } return node }