forked from simoneguidi94/gopapageno
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtoken.go
101 lines (75 loc) · 1.92 KB
/
token.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package gopapageno
import (
"fmt"
"strings"
)
type TokenType uint16
const (
TokenEmpty TokenType = 0
TokenTerm TokenType = 0x8000
)
func (t TokenType) IsTerminal() bool {
return t >= 0x8000
}
func (t TokenType) Value() uint16 {
return uint16(0x7FFF & t)
}
type Token struct {
Type TokenType
Precedence Precedence
Value any
Next *Token
Child *Token
LastChild *Token
}
func (t *Token) IsTerminal() bool {
return t.Type.IsTerminal()
}
// Height computes the height of the AST rooted in `t`.
// It can be used as an evaluation metric for tree-balance, as left/right-skewed trees will have a bigger height compared to balanced trees.
func (t *Token) Height() int {
var rec func(t *Token, depth int) int
rec = func(t *Token, depth int) int {
if t == nil {
return depth
}
return max(rec(t.Child, depth+1), rec(t.Next, depth))
}
return rec(t, 0)
}
// Size returns the number of tokens in the AST rooted in `t`.
func (t *Token) Size() int {
var rec func(t *Token) int
rec = func(t *Token) int {
if t == nil {
return 0
}
return 1 + rec(t.Child) + rec(t.Next)
}
return rec(t)
}
// String returns a string representation of the AST rooted in `t`.
// This should be used rarely, as it doesn't print out a proper string representation of the token type.
// Gopapageno will generate a `SprintToken` function for your tokens.
func (t *Token) String() string {
var sprintRec func(t *Token, sb *strings.Builder, indent string)
sprintRec = func(t *Token, sb *strings.Builder, indent string) {
if t == nil {
return
}
sb.WriteString(indent)
if t.Next == nil {
sb.WriteString("└── ")
indent += " "
} else {
sb.WriteString("├── ")
indent += "| "
}
sb.WriteString(fmt.Sprintf("%d: %v\n", t.Type, t.Value))
sprintRec(t.Child, sb, indent)
sprintRec(t.Next, sb, indent[:len(indent)-4])
}
var sb strings.Builder
sprintRec(t, &sb, "")
return sb.String()
}