-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse.go
145 lines (128 loc) · 2.84 KB
/
parse.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package combinator
import (
"errors"
"fmt"
"strings"
"unicode/utf8"
)
// Parses a statement into a tree
func parse(statement string) *Tree {
if len(statement) == 0 {
return nil
}
// Returns a single-node tree if there is only one character
if utf8.RuneCountInString(statement) == 1 {
return &Tree{
IsRoot: true,
IsLeaf: true,
Leaf: statement,
}
}
var root *Tree
for _, subStatement := range getSubStatements(statement) {
// Recursively parse each substatement
subTree := parse(subStatement)
subTree.IsRoot = false
// Send the subtree down the left-most spine
if root == nil {
root = subTree
} else {
root = &Tree{
Left: root,
Right: subTree,
}
root.Left.Parent = root
root.Right.Parent = root
}
}
// Return our tree, ensuring the root boolean is set
root.IsRoot = true
return root
}
// Returns a slice of sub statements. For `f(xy)z`, the
// sub statements are `f`, `xy`, and `z` are sub statements
func getSubStatements(statement string) []string {
subStatements := []string{}
var count int
var tempStatement strings.Builder
for _, ch := range statement {
switch ch {
case '(':
if count > 0 {
tempStatement.WriteRune(ch)
}
count++
case ')':
count--
if count > 0 {
tempStatement.WriteRune(ch)
}
if count == 0 {
subStatements = append(subStatements, tempStatement.String())
tempStatement.Reset()
}
default:
if count > 0 {
tempStatement.WriteRune(ch)
} else {
subStatements = append(subStatements, string(ch))
}
}
}
return subStatements
}
// Unparses a tree into a string statement
func unparse(root *Tree) string {
var statement strings.Builder
// Start with the left-most leaf
current := getLeftMostLeaf(root)
statement.WriteString(current.Leaf)
for {
// When we get to the root, we are done
if current == root {
break
}
// Move up the tree
current = current.Parent
// Recursively unparse the right child
if current.Right.IsLeaf {
statement.WriteString(unparse(current.Right))
} else {
statement.WriteString(fmt.Sprintf("(%s)", unparse(current.Right)))
}
}
return statement.String()
}
// Checks if the statement is well-defined
func isWellDefined(statement string) error {
// Empty statements don't make much sense
if len(statement) == 0 {
return errors.New("statement cannot be empty")
}
var count int
var prevCharOpenParen bool
for _, ch := range statement {
switch ch {
case '(':
count++
prevCharOpenParen = true
case ')':
// No `()`
if prevCharOpenParen {
return errors.New("parens cannot be empty ()")
}
// No `x)`
if count == 0 {
return errors.New("closed paren must have open paren")
}
count--
default:
prevCharOpenParen = false
}
}
// Parentheses obviously must match
if count != 0 {
return errors.New("parens do not match")
}
return nil
}