-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwhitespaces.py
202 lines (166 loc) · 5.87 KB
/
whitespaces.py
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# encoding: utf-8
import re
from collections import namedtuple
from parsing_future import is_text
from imports import expect, Expecting
from parsing.core import ParserElement
from parsing.results import ParseResults
from parsing.utils import Log, indent, quote, regex_range, alphanums, regex_iso
Literal, Token, Empty = expect("Literal", "Token", "Empty")
CURRENT = None # THE CURRENT DEFINED WHITESPACE
NO_WHITESPACE = None # NOTHING IS WHITESPACE ENGINE
STANDARD_WHITESPACE = None # SIMPLE WHITESPACE
whitespace_stack = []
class Whitespace(ParserElement):
def __init__(self, white=" \n\r\t"):
self.id = id(self)
self.literal = Literal
self.keyword_chars = alphanums + "_$"
self.ignore_list = []
self.debug_actions = DebugActions(noop, noop, noop)
self.all_exceptions = {}
self.content = None
self.skips = {}
self.regex = None
self.expr = None
self.set_whitespace(white)
self.parent = None
self.copies = []
def copy(self):
output = Whitespace(self.white_chars)
output.id = self.id
output.literal = self.literal
output.keyword_chars = self.keyword_chars
output.ignore_list = list(self.ignore_list)
output.debug_actions = self.debug_actions
output.all_exceptions = self.all_exceptions
output.content = None
output.skips = {}
output.regex = self.regex
output.expr = self.expr
output.parent = self
output.copies = []
return output
def __enter__(self):
global CURRENT
whitespace_stack.append(CURRENT)
CURRENT = new_whitespace = self.copy()
self.copies.append(new_whitespace)
return new_whitespace
use = __enter__
def __exit__(self, exc_type, exc_val, exc_tb):
"""
REMOVE THIS WHITESPACE CONTEXT
:return:
"""
global CURRENT
if self.copies and self.copies[-1] is CURRENT:
self.copies.pop()
CURRENT = whitespace_stack.pop()
return
if self.parent:
self.parent.__exit__(exc_type, exc_val, exc_tb)
self.parent = None
return
Log.error("Released wrong whitespace")
def release(self):
self.__exit__(None, None, None)
def normalize(self, expr):
if expr == None:
return None
if is_text(expr):
return self.literal(expr)
if isinstance(expr, type) and issubclass(expr, ParserElement):
return expr() # ALLOW Empty WHEN Empty() WAS INTENDED
if not isinstance(expr, ParserElement):
Log.error("expecting string, or ParserElemenet")
return expr
def record_exception(self, string, loc, expr, exc):
es = self.all_exceptions.setdefault(loc, [])
es.append(exc)
def set_literal(self, literal):
self.id = id(self)
self.literal = literal
def set_keyword_chars(self, chars):
self.id = id(self)
self.keyword_chars = "".join(sorted(set(chars)))
def set_whitespace(self, chars):
self.id = id(self)
self.white_chars = "".join(sorted(set(chars)))
self.content = None
self.expr = None if isinstance(Empty, Expecting) else Empty()
self.regex = re.compile(self.__regex__()[1], re.DOTALL)
def add_ignore(self, *ignore_exprs):
"""
ADD TO THE LIST OF IGNORED EXPRESSIONS
:param ignore_expr:
"""
self.id = id(self)
for ignore_expr in ignore_exprs:
ignore_expr = ignore_expr.suppress()
self.ignore_list.append(ignore_expr)
self.content = None
self.expr = None if isinstance(Empty, Expecting) else Empty()
self.regex = re.compile(self.__regex__()[1], re.DOTALL)
return self
def backup(self):
return Backup(self)
def parse_impl(self, string, start, do_actions=True):
end = self.skip(string, start)
return ParseResults(
self.expr, start, end, [], ["add exceptions for missed whitespace"]
)
def skip(self, string, start):
"""
:return: next non-whitespace position
"""
if not self.ignore_list and not self.white_chars:
return start
if string is self.content:
try:
end = self.skips[start]
if end != -1:
return end
except IndexError:
return start
else:
num = len(string)
self.skips = [-1] * num
self.content = string
if start >= num:
return start
end = start # TO AVOID RECURSIVE LOOP
found = self.regex.match(string, start)
if found:
end = found.end()
self.skips[start] = end # THE REAL VALUE
return end
def __regex__(self):
white = regex_range(self.white_chars)
if not self.ignore_list:
if not white:
return "*", ""
else:
return "*", white + "*"
ignored = "|".join(regex_iso(*i.__regex__(), "|") for i in self.ignore_list)
return "+", f"(?:{white}*(?:{ignored}))*{white}*"
def __str__(self):
output = ["{"]
for k, v in self.__dict__.items():
value = str(v)
output.append(indent(quote(k) + ":" + value))
output.append("}")
return "\n".join(output)
class Backup(object):
def __init__(self, whitespace):
self.whitespace = whitespace
self.content = whitespace.content
self.skips = whitespace.skips
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
self.whitespace.content = self.content
self.whitespace.skips = self.skips
def noop(*args):
return
DebugActions = namedtuple("DebugActions", ["TRY", "MATCH", "FAIL"])