Skip to content

Commit

Permalink
Sync SGF-Parsing (#2902)
Browse files Browse the repository at this point in the history
Co-authored-by: Kah Goh <[email protected]>
  • Loading branch information
jagdish-15 and kahgoh authored Jan 28, 2025
1 parent 6488e34 commit 0bb6ea4
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 29 deletions.
4 changes: 4 additions & 0 deletions exercises/practice/sgf-parsing/.meta/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
"authors": [
"tlphat"
],
"contributors": [
"jagdish-15",
"kahgoh"
],
"files": {
"solution": [
"src/main/java/SgfParsing.java"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,52 @@ private int parseFromIndex(String input, int index, SgfNode root) throws SgfPars
StringBuilder buffer = new StringBuilder();
Map<String, List<String>> properties = new HashMap<>();
String key = null;
boolean escape = false;
boolean inValue = false;
while (index < input.length()) {
switch (input.charAt(index)) {
case '(':
index = addNewChild(input, index, root);
break;
case ')':
break;
case '[':
key = loadKeyFromBuffer(buffer, properties);
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);
break;
default:
index = appendCharToBuffer(input, index, buffer);
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;
}
Expand Down Expand Up @@ -101,14 +127,13 @@ private int examineNextNode(String input, int index, SgfNode root, Map<String, L
}
return index;
}

private int appendCharToBuffer(String input, int index, StringBuilder buffer) {
char character = input.charAt(index);
while (character == '\\') {
character = input.charAt(++index);

private void appendChar(StringBuilder builder, char charToAdd) {
if (charToAdd != '\n' && Character.isWhitespace(charToAdd)) {
builder.append(" ");
} else {
builder.append(charToAdd);
}
buffer.append(character);
return index;
}

private void checkIfThereAreDelimiters(StringBuilder buffer) throws SgfParsingException {
Expand Down
35 changes: 35 additions & 0 deletions exercises/practice/sgf-parsing/.meta/tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,40 @@ description = "two child trees"
[724eeda6-00db-41b1-8aa9-4d5238ca0130]
description = "multiple property values"

[28092c06-275f-4b9f-a6be-95663e69d4db]
description = "within property values, whitespace characters such as tab are converted to spaces"

[deaecb9d-b6df-4658-aa92-dcd70f4d472a]
description = "within property values, newlines remain as newlines"

[8e4c970e-42d7-440e-bfef-5d7a296868ef]
description = "escaped closing bracket within property value becomes just a closing bracket"

[cf371fa8-ba4a-45ec-82fb-38668edcb15f]
description = "escaped backslash in property value becomes just a backslash"

[dc13ca67-fac0-4b65-b3fe-c584d6a2c523]
description = "opening bracket within property value doesn't need to be escaped"

[a780b97e-8dbb-474e-8f7e-4031902190e8]
description = "semicolon in property value doesn't need to be escaped"

[0b57a79e-8d89-49e5-82b6-2eaaa6b88ed7]
description = "parentheses in property value don't need to be escaped"

[c72a33af-9e04-4cc5-9890-1b92262813ac]
description = "escaped tab in property value is converted to space"

[3a1023d2-7484-4498-8d73-3666bb386e81]
description = "escaped newline in property value is converted to nothing at all"

[25abf1a4-5205-46f1-8c72-53273b94d009]
description = "escaped t and n in property value are just letters, not whitespace"

[08e4b8ba-bb07-4431-a3d9-b1f4cdea6dab]
description = "mixing various kinds of whitespace and escaped characters in property value"
reimplements = "11c36323-93fc-495d-bb23-c88ee5844b8c"

[11c36323-93fc-495d-bb23-c88ee5844b8c]
description = "escaped property"
include = false
109 changes: 106 additions & 3 deletions exercises/practice/sgf-parsing/src/test/java/SgfParsingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,114 @@ public void multiplePropertyValues() throws SgfParsingException {

@Test
@Disabled("Remove to run test")
public void escapedProperty() throws SgfParsingException {
String input = "(;A[\\]b\nc\nd\t\te \n\\]])";
SgfNode expected = new SgfNode(Map.of("A", List.of("]b\nc\nd\t\te \n]")));
public void withinPropertyValueWhitespace() throws SgfParsingException {
String input = "(;A[hello\t\tworld])";
SgfNode expected = new SgfNode(Map.of("A", List.of("hello world")));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}

@Test
@Disabled("Remove to run test")
public void withinPropertyValueNewline() throws SgfParsingException {
String input = "(;A[hello\n\nworld])";
SgfNode expected = new SgfNode(Map.of("A", List.of("hello\n\nworld")));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}

@Test
@Disabled("Remove to run test")
public void escapedClosingBracket() throws SgfParsingException {
String input = "(;A[\\]])";
SgfNode expected = new SgfNode(Map.of("A", List.of("]")));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}

@Test
@Disabled("Remove to run test")
public void escapedBacklash() throws SgfParsingException {
String input = "(;A[\\\\])";
SgfNode expected = new SgfNode(Map.of("A", List.of("\\")));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}

@Test
@Disabled("Remove to run test")
public void openingBracketNeedNotToBeEscaped() throws SgfParsingException {
String input = "(;A[x[y\\]z][foo]B[bar];C[baz])";
SgfNode expected = new SgfNode(Map.of("A", List.of("x[y]z", "foo"),
"B", List.of("bar")),
List.of(
new SgfNode(Map.of("C", List.of("baz")))
));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}

@Test
@Disabled("Remove to run test")
public void semicolonNeedNotToBeEscaped() throws SgfParsingException {
String input = "(;A[a;b][foo]B[bar];C[baz])";
SgfNode expected = new SgfNode(Map.of("A", List.of("a;b", "foo"),
"B", List.of("bar")),
List.of(
new SgfNode(Map.of("C", List.of("baz")))
));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}

@Test
@Disabled("Remove to run test")
public void paranthesesNeedNotToBeEscaped() throws SgfParsingException {
String input = "(;A[x(y)z][foo]B[bar];C[baz])";
SgfNode expected = new SgfNode(Map.of("A", List.of("x(y)z", "foo"),
"B", List.of("bar")),
List.of(
new SgfNode(Map.of("C", List.of("baz")))
));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}

@Test
@Disabled("Remove to run test")
public void escapedTab() throws SgfParsingException {
String input = "(;A[hello\\\tworld])";
SgfNode expected = new SgfNode(Map.of("A", List.of("hello world")));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}

@Test
@Disabled("Remove to run test")
public void escapedNewline() throws SgfParsingException {
String input = "(;A[hello\\\nworld])";
SgfNode expected = new SgfNode(Map.of("A", List.of("helloworld")));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}


@Test
@Disabled("Remove to run test")
public void escapedTAndN() throws SgfParsingException {
String input = "(;A[\\t = t and \\n = n])";
SgfNode expected = new SgfNode(Map.of("A", List.of("t = t and n = n")));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}


@Test
@Disabled("Remove to run test")
public void mixOfEscapedCharactersAndWhitespaces() throws SgfParsingException {
String input = "(;A[\\]b\nc\\\nd\t\te\\\\ \\\n\\]])";
SgfNode expected = new SgfNode(Map.of("A", List.of("]b\ncd e\\ ]")));
SgfNode actual = new SgfParsing().parse(input);
assertThat(actual).isEqualTo(expected);
}
}

0 comments on commit 0bb6ea4

Please sign in to comment.