impossible

Finished
2626
2727
2828def parse(input_string: str) -> SgfTree:
29 pass
29 # Edge Case: Empty input or doesn't start with '('
30 if not input_string or input_string[0] != '(':
31 raise ValueError("tree missing")
32
33 # Edge Case: Doesn't end with ')'
34 if input_string[-1] != ')':
35 raise ValueError("tree missing")
36
37 # Remove the outer parentheses
38 content = input_string[1:-1]
39
40 # Edge Case: Empty content after removing parentheses
41 if not content:
42 raise ValueError("tree with no nodes")
43
44 # Edge Case: Doesn't start with ';'
45 if content[0] != ';':
46 raise ValueError("tree with no nodes")
47
48 return _parse_tree(content)
49
50
51def _parse_tree(content: str) -> SgfTree:
52 # Find the first node
53 if not content or content[0] != ';':
54 raise ValueError("tree with no nodes")
55
56 # Parse the node
57 node_content, remaining = _parse_node(content[1:])
58
59 # Parse children
60 children = []
61 while remaining:
62 if remaining[0] == '(':
63 # Parse a subtree
64 subtree_content, remaining = _parse_subtree(remaining)
65 children.append(_parse_tree(subtree_content))
66 else:
67 # No more children
68 break
69
70 return SgfTree(properties=node_content, children=children)
71
72
73def _parse_subtree(content: str) -> tuple[str, str]:
74 if content[0] != '(':
75 raise ValueError("tree missing")
76
77 depth = 1
78 i = 1
79 while i < len(content) and depth > 0:
80 if content[i] == '(':
81 depth += 1
82 elif content[i] == ')':
83 depth -= 1
84 i += 1
85
86 # Edge Case: Unmatched parentheses
87 if depth != 0:
88 raise ValueError("tree missing")
89
90 return content[1:i-1], content[i:]
91
92
93def _parse_node(content: str) -> tuple[dict, str]:
94 properties = {}
95 i = 0
96
97 while i < len(content):
98 # Check if we've reached the end of the node (start of child or end of current tree)
99 if content[i] in ';(' or i == len(content):
100 break
101
102 # Parse property key
103 key_start = i
104 while i < len(content) and content[i].isalpha():
105 i += 1
106
107 # Edge Case: No key found
108 if i == key_start:
109 raise ValueError("properties without delimiter")
110
111 key = content[key_start:i]
112
113 # Edge Case: Key is not uppercase
114 if key != key.upper():
115 raise ValueError("property must be in uppercase")
116
117 # Parse values
118 values = []
119
120 # Edge Case: No values after key
121 if i >= len(content) or content[i] != '[':
122 raise ValueError("properties without delimiter")
123
124 while i < len(content) and content[i] == '[':
125 i += 1 # Skip '['
126 value_start = i
127
128 # Parse value
129 while i < len(content) and content[i] != ']':
130 if content[i] == '\\':
131 i += 2 # Skip escape character and the next character
132 else:
133 i += 1
134
135 # Edge Case: Unmatched bracket
136 if i >= len(content) or content[i] != ']':
137 raise ValueError("properties without delimiter")
138
139 value = _unescape_text(content[value_start:i])
140 values.append(value)
141 i += 1 # Skip ']'
142
143 properties[key] = values
144
145 return properties, content[i:]
146
147
148def _unescape_text(text: str) -> str:
149 result = []
150 i = 0
151 while i < len(text):
152 if text[i] == '\\':
153 i += 1
154 if i < len(text):
155 char = text[i]
156 # Newlines are removed if they come immediately after a backslash
157 if char == '\n':
158 pass # Remove the newline
159 # All whitespace characters other than newline are converted to spaces
160 elif char in ' \t\r':
161 result.append(' ')
162 # Any non-whitespace character after \ is inserted as-is
163 else:
164 result.append(char)
165 else:
166 char = text[i]
167 # All whitespace characters other than newline are converted to spaces
168 if char in ' \t\r':
169 result.append(' ')
170 else:
171 result.append(char)
172 i += 1
173 return ''.join(result)
174# Handled Edge Cases: Empty input, doesn't start with '(', doesn't end with ')', empty content after removing parentheses, doesn't start with ';', unmatched parentheses, no key found, key is not uppercase, no values after key, unmatched bracket, newline after backslash, whitespace conversion
Test NameStatus
test_opening_bracket_within_property_value_doesn_t_need_to_be_escaped
Fail
test_parentheses_in_property_value_don_t_need_to_be_escaped
Fail
test_semicolon_in_property_value_doesn_t_need_to_be_escaped
Fail
test_two_nodes
Fail
test_all_lowercase_property
Pass
test_empty_input
Pass
test_escaped_backslash_in_property_value_becomes_just_a_backslash
Pass
test_escaped_closing_bracket_within_property_value_becomes_just_a_closing_bracket
Pass
test_escaped_newline_in_property_value_is_converted_to_nothing_at_all
Pass
test_escaped_t_and_n_in_property_value_are_just_letters_not_whitespace
Pass
test_escaped_tab_in_property_value_is_converted_to_space
Pass
test_mixing_various_kinds_of_whitespace_and_escaped_characters_in_property_value
Pass
test_multiple_properties
Pass
test_multiple_property_values
Pass
test_node_without_properties
Pass
test_node_without_tree
Pass
test_properties_without_delimiter
Pass
test_single_node_tree
Pass
test_tree_with_no_nodes
Pass
test_two_child_trees
Pass
test_upper_and_lowercase_property
Pass
test_within_property_values_newlines_remain_as_newlines
Pass
test_within_property_values_whitespace_characters_such_as_tab_are_converted_to_spaces
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.