forked from exercism/java
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSgfParsing.java
145 lines (131 loc) · 4.92 KB
/
SgfParsing.java
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
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SgfParsing {
public SgfNode parse(String input) throws SgfParsingException {
checkIfTreeHasAnyNode(input);
checkIfTreeExists(input);
SgfNode tree = new SgfNode();
parseFromIndex(input, 2, tree);
return tree;
}
private void checkIfTreeHasAnyNode(String input) throws SgfParsingException {
if ("()".equals(input)) {
throw new SgfParsingException("tree with no nodes");
}
}
private void checkIfTreeExists(String input) throws SgfParsingException {
if (input.isEmpty() || !input.startsWith("(;")) {
throw new SgfParsingException("tree missing");
}
}
private int parseFromIndex(String input, int index, SgfNode root) throws SgfParsingException {
StringBuilder buffer = new StringBuilder();
Map<String, List<String>> properties = new HashMap<>();
String key = null;
boolean escape = false;
boolean inValue = false;
while (index < input.length()) {
char nextChar = input.charAt(index);
if (escape) {
if (nextChar != '\n') {
appendChar(buffer, nextChar);
}
escape = false;
} else {
switch (nextChar) {
case '(':
if (inValue) {
buffer.append(nextChar);
} else {
index = addNewChild(input, index, root);
}
break;
case ')':
if (inValue) {
buffer.append(nextChar);
}
break;
case '[':
if (inValue) {
buffer.append(nextChar);
} else {
key = loadKeyFromBuffer(buffer, properties);
inValue = true;
}
break;
case ']':
properties.get(key).add(popStringFromBuffer(buffer));
if (input.charAt(index + 1) == ')') {
root.setProperties(properties);
return index + 1;
}
index = examineNextNode(input, index, root, properties);
inValue = false;
break;
case '\\':
escape = true;
break;
default:
appendChar(buffer, nextChar);
}
}
++index;
}
checkIfThereAreDelimiters(buffer);
return index;
}
private int addNewChild(String input, int index, SgfNode root) throws SgfParsingException {
SgfNode node = new SgfNode();
root.appendChild(node);
return parseFromIndex(input, index + 2, node);
}
private String loadKeyFromBuffer(StringBuilder buffer, Map<String, List<String>> properties)
throws SgfParsingException {
String key = popStringFromBuffer(buffer);
checkIfKeyUppercase(key);
properties.put(key, new ArrayList<>());
return key;
}
private String popStringFromBuffer(StringBuilder stringBuilder) {
String toReturn = stringBuilder.toString();
stringBuilder.setLength(0);
return toReturn;
}
private void checkIfKeyUppercase(String key) throws SgfParsingException {
if (!isUppercase(key)) {
throw new SgfParsingException("property must be in uppercase");
}
}
private boolean isUppercase(String key) {
return key.equals(key.toUpperCase());
}
private int examineNextNode(String input, int index, SgfNode root, Map<String, List<String>> properties)
throws SgfParsingException {
char nextChar = input.charAt(index + 1);
if (nextChar == '[') {
++index;
} else if (nextChar == '(' || nextChar == ';') {
root.setProperties(properties);
if (nextChar == '(') {
index = addNewChild(input, index + 1, root);
} else {
index = addNewChild(input, index, root);
}
}
return index;
}
private void appendChar(StringBuilder builder, char charToAdd) {
if (charToAdd != '\n' && Character.isWhitespace(charToAdd)) {
builder.append(" ");
} else {
builder.append(charToAdd);
}
}
private void checkIfThereAreDelimiters(StringBuilder buffer) throws SgfParsingException {
if (buffer.length() != 0) {
throw new SgfParsingException("properties without delimiter");
}
}
}