-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathnested_parser.py
More file actions
137 lines (102 loc) · 2.76 KB
/
nested_parser.py
File metadata and controls
137 lines (102 loc) · 2.76 KB
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
#encoding=utf-8
import string
_OPEN_TO_CLOSE = {
'{': '}',
'[': ']',
'(': ')',
}
_CLOSE_SET = set(_OPEN_TO_CLOSE.values())
def split_top_level(text, delimiter, skip_empty = False):
if text is None:
return []
if not delimiter:
raise ValueError('delimiter can not be empty')
values = []
stack = []
start = 0
i = 0
n = len(text)
while i < n:
c = text[i]
if c == '\\' and i + 1 < n:
i += 2
continue
if c in _OPEN_TO_CLOSE:
stack.append(_OPEN_TO_CLOSE[c])
i += 1
continue
if c in _CLOSE_SET:
if not stack or c != stack[-1]:
raise ValueError('%s is not a legal nested expression' % text)
stack.pop()
i += 1
continue
if not stack and text.startswith(delimiter, i):
value = text[start:i]
if not skip_empty or value:
values.append(value)
i += len(delimiter)
start = i
continue
i += 1
if stack:
raise ValueError('%s is not a legal nested expression' % text)
value = text[start:]
if not skip_empty or value:
values.append(value)
return values
def unwrap_container(text, begin, end):
value = text.strip()
if len(value) >= 2 and value[0] == begin and value[-1] == end:
return value[1:-1]
return value
def split_list_values(value):
return split_top_level(unwrap_container(value, '[', ']'), ',', True)
def split_obj_type_fields(type_, separator):
return split_top_level(unwrap_container(type_, '{', '}'), separator, True)
def split_obj_values(value, separator):
return split_top_level(unwrap_container(value, '{', '}'), separator, True)
def split_field_declaration(text):
declaration = text.strip()
if not declaration:
raise ValueError('field declaration can not be empty')
values = []
stack = []
start = None
i = 0
n = len(declaration)
while i < n:
c = declaration[i]
if c == '\\' and i + 1 < n:
if start is None:
start = i
i += 2
continue
if c in _OPEN_TO_CLOSE:
if start is None:
start = i
stack.append(_OPEN_TO_CLOSE[c])
i += 1
continue
if c in _CLOSE_SET:
if not stack or c != stack[-1]:
raise ValueError('%s is not a legal field declaration' % declaration)
stack.pop()
i += 1
continue
if c in string.whitespace and not stack:
if start is not None:
values.append(declaration[start:i])
start = None
i += 1
continue
if start is None:
start = i
i += 1
if stack:
raise ValueError('%s is not a legal field declaration' % declaration)
if start is not None:
values.append(declaration[start:])
if len(values) < 2:
raise ValueError('%s is not a legal field declaration' % declaration)
return (' '.join(values[:-1]), values[-1])