Skip to content

Commit 1939770

Browse files
authored
Merge pull request #151 from ianlewis/98-feature-utilities-for-printing-tokens-and-trees
feat: add fmt.Stringer implementation for Node
2 parents e14f106 + 32c6480 commit 1939770

2 files changed

Lines changed: 101 additions & 2 deletions

File tree

parser.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package lexparse
1717
import (
1818
"context"
1919
"errors"
20+
"fmt"
2021
"io"
2122
)
2223

@@ -30,8 +31,42 @@ type Node[V comparable] struct {
3031
Start Position
3132
}
3233

33-
// ParseState is the state of the current parsing state machine. It defines the logic
34-
// to process the current state and returns the next state.
34+
func (n *Node[V]) String() string {
35+
return fmtNode(n, nil)
36+
}
37+
38+
func fmtNode[V comparable](node *Node[V], lastRank []bool) string {
39+
nodeStr := ""
40+
41+
for i := range len(lastRank) - 1 {
42+
if lastRank[i] {
43+
nodeStr += " "
44+
} else {
45+
nodeStr += "│ "
46+
}
47+
}
48+
49+
if len(lastRank) > 0 {
50+
if lastRank[len(lastRank)-1] {
51+
nodeStr += "└── "
52+
} else {
53+
nodeStr += "├── "
54+
}
55+
}
56+
57+
nodeStr += fmt.Sprintf("%v (%v)\n", node.Value, node.Start)
58+
for i, child := range node.Children {
59+
newLastRank := make([]bool, len(lastRank)+1)
60+
copy(newLastRank, lastRank)
61+
newLastRank[len(lastRank)] = i == len(node.Children)-1
62+
nodeStr += fmtNode(child, newLastRank)
63+
}
64+
65+
return nodeStr
66+
}
67+
68+
// ParseState is the state of the current parsing state machine. It defines the
69+
// logic to process the current state and returns the next state.
3570
type ParseState[V comparable] interface {
3671
// Run executes the logic at the current state, returning an error if one is
3772
// encountered. Implementations are expected to add new [Node] objects to

parser_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,67 @@ func TestParser_Replace_root(t *testing.T) {
524524
t.Errorf("p.root (-want, +got): \n%s", diff)
525525
}
526526
}
527+
528+
func TestNode_String(t *testing.T) {
529+
t.Parallel()
530+
531+
node := &Node[string]{
532+
Value: "root",
533+
Start: Position{
534+
Offset: 0,
535+
Line: 1,
536+
Column: 1,
537+
},
538+
Children: []*Node[string]{
539+
{
540+
Value: "child1",
541+
542+
Start: Position{
543+
Offset: 1,
544+
Line: 1,
545+
Column: 2,
546+
},
547+
Children: []*Node[string]{
548+
{
549+
Value: "grandchild1",
550+
551+
Start: Position{
552+
Offset: 2,
553+
Line: 1,
554+
Column: 3,
555+
},
556+
},
557+
},
558+
},
559+
{
560+
Value: "child2",
561+
Start: Position{
562+
Offset: 3,
563+
Line: 1,
564+
Column: 4,
565+
},
566+
Children: []*Node[string]{
567+
{
568+
Value: "grandchild2",
569+
Start: Position{
570+
Offset: 4,
571+
Line: 1,
572+
Column: 5,
573+
},
574+
},
575+
},
576+
},
577+
},
578+
}
579+
580+
expected := `root (1:1)
581+
├── child1 (1:2)
582+
│ └── grandchild1 (1:3)
583+
└── child2 (1:4)
584+
└── grandchild2 (1:5)
585+
`
586+
587+
if diff := cmp.Diff(expected, node.String()); diff != "" {
588+
t.Errorf("Node.String() (-want, +got): \n%s", diff)
589+
}
590+
}

0 commit comments

Comments
 (0)