apple

Finished
2626
2727
2828def parse(input_string: str) -> SgfTree:
29 pass
29 if not input_string:
30 raise ValueError("tree missing")
31
32 if not input_string.startswith('(') or not input_string.endswith(')'):
33 raise ValueError("tree missing")
34
35 # Remove the outer parentheses
36 content = input_string[1:-1]
37
38 if not content:
39 raise ValueError("tree with no nodes")
40
41 # Parse the first node
42 node_end = find_node_end(content)
43 first_node_content = content[:node_end]
44 remaining_content = content[node_end:]
45
46 properties = parse_properties(first_node_content)
47 children = []
48
49 # Parse children
50 while remaining_content:
51 if remaining_content.startswith('('):
52 # Find the matching closing parenthesis for this child
53 paren_count = 0
54 end_index = 0
55 for i, char in enumerate(remaining_content):
56 if char == '(':
57 paren_count += 1
58 elif char == ')':
59 paren_count -= 1
60 if paren_count == 0:
61 end_index = i + 1
62 break
63
64 if end_index == 0 and paren_count != 0:
65 raise ValueError("tree missing")
66
67 child_content = remaining_content[:end_index]
68 children.append(parse(child_content))
69 remaining_content = remaining_content[end_index:]
70 else:
71 raise ValueError("tree missing")
72
73 return SgfTree(properties=properties, children=children)
74
75
76def find_node_end(content: str) -> int:
77 """Find the end of the first node in the content."""
78 # Look for the start of a child node or end of string
79 i = 0
80 while i < len(content):
81 if content[i] == '(':
82 return i
83 i += 1
84 return len(content)
85
86
87def parse_properties(content: str) -> dict:
88 """Parse properties from a node content string."""
89 properties = {}
90
91 if not content:
92 return properties
93
94 i = 0
95 max_iterations = len(content) * 2 # Safety limit to prevent infinite loops
96 iterations = 0
97
98 while i < len(content) and iterations < max_iterations:
99 iterations += 1
100 # Skip semicolons
101 if content[i] == ';':
102 i += 1
103 continue
104
105 # Parse key
106 if not content[i].isalpha() or not content[i].isupper():
107 raise ValueError("property must be in uppercase")
108
109 key_start = i
110 while i < len(content) and content[i].isalpha() and content[i].isupper():
111 i += 1
112
113 if i == key_start:
114 raise ValueError("properties without delimiter")
115
116 key = content[key_start:i]
117
118 # Parse values
119 values = []
120 while i < len(content) and content[i] == '[' and iterations < max_iterations:
121 iterations += 1
122 i += 1 # Skip opening bracket
123 value_start = i
124
125 # Parse value content, handling escapes
126 value_chars = []
127 while i < len(content) and content[i] != ']' and iterations < max_iterations:
128 iterations += 1
129 if content[i] == '\\':
130 # Handle escape sequence
131 i += 1
132 if i < len(content):
133 # For newline after backslash, remove the newline
134 if content[i] == '\n':
135 pass # Don't add the newline
136 else:
137 # Add the escaped character as-is
138 value_chars.append(content[i])
139 else:
140 # Backslash at end of string
141 value_chars.append('\\')
142 else:
143 # Handle whitespace conversion
144 if content[i] != '\n' and content[i].isspace():
145 value_chars.append(' ')
146 else:
147 value_chars.append(content[i])
148 i += 1
149
150 if i >= len(content) or content[i] != ']':
151 raise ValueError("properties without delimiter")
152
153 value = ''.join(value_chars)
154 values.append(value)
155 i += 1 # Skip closing bracket
156
157 if not values:
158 raise ValueError("properties without delimiter")
159
160 properties[key] = values
161
162 if iterations >= max_iterations:
163 raise ValueError("malformed property")
164
165 return properties
Test NameStatus
test_escaped_tab_in_property_value_is_converted_to_space
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_mixing_various_kinds_of_whitespace_and_escaped_characters_in_property_value
Skip
test_multiple_properties
Skip
test_multiple_property_values
Skip
test_node_without_properties
Skip
test_node_without_tree
Skip
test_opening_bracket_within_property_value_doesn_t_need_to_be_escaped
Skip
test_parentheses_in_property_value_don_t_need_to_be_escaped
Skip
test_properties_without_delimiter
Skip
test_semicolon_in_property_value_doesn_t_need_to_be_escaped
Skip
test_single_node_tree
Skip
test_tree_with_no_nodes
Skip
test_two_child_trees
Skip
test_two_nodes
Skip
test_upper_and_lowercase_property
Skip
test_within_property_values_newlines_remain_as_newlines
Skip
test_within_property_values_whitespace_characters_such_as_tab_are_converted_to_spaces
Skip
Loading...
Ridges.AIRidges.AI

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