ZedScripts 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ZedScripts/__about__.py +1 -0
- ZedScripts/__init__.py +38 -0
- ZedScripts/enums/Diagnostic.py +165 -0
- ZedScripts/enums/SyntaxErrorType.py +7 -0
- ZedScripts/environment/__init__.py +33 -0
- ZedScripts/environment/config.py +82 -0
- ZedScripts/environment/document.py +374 -0
- ZedScripts/environment/mod.py +62 -0
- ZedScripts/environment/version.py +202 -0
- ZedScripts/environment/workspace.py +320 -0
- ZedScripts/locale/en.json +38 -0
- ZedScripts/main.py +7 -0
- ZedScripts/providers/actions.py +13 -0
- ZedScripts/providers/capabilities.py +107 -0
- ZedScripts/providers/configuration.py +26 -0
- ZedScripts/providers/debug.py +59 -0
- ZedScripts/providers/diagnostics.py +101 -0
- ZedScripts/providers/hover.py +37 -0
- ZedScripts/providers/http.py +49 -0
- ZedScripts/providers/locale.py +80 -0
- ZedScripts/providers/notifications.py +45 -0
- ZedScripts/providers/semantic_tokens.py +189 -0
- ZedScripts/scripts/__init__.py +160 -0
- ZedScripts/scripts/block.py +547 -0
- ZedScripts/scripts/dataset.py +355 -0
- ZedScripts/scripts/value.py +706 -0
- ZedScripts/scripts/version.py +75 -0
- ZedScripts/server.py +288 -0
- ZedScripts/structure/ast.py +143 -0
- ZedScripts/structure/lexer.py +482 -0
- ZedScripts/structure/parser.py +243 -0
- ZedScripts/utils.py +85 -0
- zedscripts-0.0.2.dist-info/METADATA +105 -0
- zedscripts-0.0.2.dist-info/RECORD +37 -0
- zedscripts-0.0.2.dist-info/WHEEL +5 -0
- zedscripts-0.0.2.dist-info/licenses/LICENSE +21 -0
- zedscripts-0.0.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import enum
|
|
4
|
+
import string
|
|
5
|
+
from typing import Any
|
|
6
|
+
from collections import UserList
|
|
7
|
+
# from warnings import deprecated
|
|
8
|
+
|
|
9
|
+
from lsprotocol import types
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TextPosition:
|
|
13
|
+
"""
|
|
14
|
+
Position in a text file.
|
|
15
|
+
Positions are zero indexed - in most cases you will want to convert to one-index when displaying to the user.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, line: int, offset: int) -> None:
|
|
19
|
+
self.line: int = line
|
|
20
|
+
self.offset: int = offset
|
|
21
|
+
|
|
22
|
+
def __hash__(self) -> int:
|
|
23
|
+
return hash((self.line, self.offset))
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def from_index(text: str, i: int, offset: TextPosition | None = None) -> TextPosition:
|
|
27
|
+
"""
|
|
28
|
+
Returns the TextPosition of a character in a string by its index.
|
|
29
|
+
:param text: The string containing the character.
|
|
30
|
+
:param i: Index of the character.
|
|
31
|
+
:param offset: If specified, the result will be offset as though the start was at this position.
|
|
32
|
+
:return: Position of the character relative to the start of the string.
|
|
33
|
+
"""
|
|
34
|
+
if offset is None:
|
|
35
|
+
offset = TextPosition(0, 0)
|
|
36
|
+
lines: int = text.count("\n", 0, i)
|
|
37
|
+
if lines == 0:
|
|
38
|
+
return TextPosition(offset.line, offset.offset + i)
|
|
39
|
+
else:
|
|
40
|
+
return TextPosition(offset.line + lines, i - text.rfind("\n", 0, i) - 1)
|
|
41
|
+
|
|
42
|
+
def to_index(self, string: str) -> int:
|
|
43
|
+
newline: int = -1
|
|
44
|
+
for _ in range(self.line):
|
|
45
|
+
newline = string.index("\n", newline + 1)
|
|
46
|
+
return newline + self.offset + 1
|
|
47
|
+
|
|
48
|
+
def relative_to(self, other: TextPosition) -> TextPosition:
|
|
49
|
+
"""
|
|
50
|
+
Returns a new TextPosition that represents the same position as this one, relative to ``other``.
|
|
51
|
+
:param other:
|
|
52
|
+
:return:
|
|
53
|
+
"""
|
|
54
|
+
assert self.line > other.line or (self.line == other.line and self.offset >= other.offset)
|
|
55
|
+
line = self.line - other.line
|
|
56
|
+
offset = self.offset
|
|
57
|
+
if line == 0:
|
|
58
|
+
offset -= other.offset
|
|
59
|
+
return TextPosition(line, offset)
|
|
60
|
+
|
|
61
|
+
def __gt__(self, other: Any) -> bool:
|
|
62
|
+
if not isinstance(other, TextPosition):
|
|
63
|
+
return NotImplemented
|
|
64
|
+
return self.line > other.line or self.line == other.line and self.offset > other.offset
|
|
65
|
+
|
|
66
|
+
def __ge__(self, other: Any) -> bool:
|
|
67
|
+
if not isinstance(other, TextPosition):
|
|
68
|
+
return NotImplemented
|
|
69
|
+
return self.line > other.line or self.line == other.line and self.offset >= other.offset
|
|
70
|
+
|
|
71
|
+
def __lt__(self, other: Any) -> bool:
|
|
72
|
+
if not isinstance(other, TextPosition):
|
|
73
|
+
return NotImplemented
|
|
74
|
+
return other > self
|
|
75
|
+
|
|
76
|
+
def __le__(self, other: Any) -> bool:
|
|
77
|
+
if not isinstance(other, TextPosition):
|
|
78
|
+
return NotImplemented
|
|
79
|
+
return other >= self
|
|
80
|
+
|
|
81
|
+
def __eq__(self, other: Any) -> bool:
|
|
82
|
+
if not isinstance(other, TextPosition):
|
|
83
|
+
return False
|
|
84
|
+
return self.line == other.line and self.offset == other.offset
|
|
85
|
+
|
|
86
|
+
def __repr__(self) -> str:
|
|
87
|
+
return f"<{str(self.line)}:{str(self.offset)}>"
|
|
88
|
+
|
|
89
|
+
def to_lsp(self) -> types.Position:
|
|
90
|
+
return types.Position(line=self.line, character=self.offset)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class TextRange:
|
|
94
|
+
"""
|
|
95
|
+
Range of characters in a text file.
|
|
96
|
+
|
|
97
|
+
Range positions should be thought of as between characters:
|
|
98
|
+
A range starting at ``0:0`` and ending at ``0:5`` contains the characters ``0:0`` - ``0:4``.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def __init__(self, start: TextPosition, end: TextPosition) -> None:
|
|
102
|
+
self.start: TextPosition = start
|
|
103
|
+
self.end: TextPosition = end
|
|
104
|
+
|
|
105
|
+
def __repr__(self) -> str:
|
|
106
|
+
return f"<{repr(self.start)}-{repr(self.end)}>"
|
|
107
|
+
|
|
108
|
+
def __hash__(self) -> int:
|
|
109
|
+
return hash((self.start, self.end))
|
|
110
|
+
|
|
111
|
+
def __eq__(self, other: Any) -> bool:
|
|
112
|
+
"""When comparing with another TextRange, check for equality. If comparing with a
|
|
113
|
+
TextPosition, check if the position is within the start and end range."""
|
|
114
|
+
if isinstance(other, TextRange):
|
|
115
|
+
return self.start == other.start and self.end == other.end
|
|
116
|
+
elif isinstance(other, TextPosition):
|
|
117
|
+
return self.start <= other and self.end >= other
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
def __lt__(self, other: Any) -> bool:
|
|
121
|
+
if isinstance(other, TextRange):
|
|
122
|
+
return (self.start, self.end) < (other.start, other.end)
|
|
123
|
+
elif isinstance(other, TextPosition):
|
|
124
|
+
return (self.start, self.end) < (other, other)
|
|
125
|
+
return NotImplemented
|
|
126
|
+
|
|
127
|
+
def __le__(self, other: Any) -> bool:
|
|
128
|
+
if isinstance(other, TextRange):
|
|
129
|
+
return (self.start, self.end) <= (other.start, other.end)
|
|
130
|
+
elif isinstance(other, TextPosition):
|
|
131
|
+
return (self.start, self.end) <= (other, other)
|
|
132
|
+
return NotImplemented
|
|
133
|
+
|
|
134
|
+
def __gt__(self, other: Any) -> bool:
|
|
135
|
+
if isinstance(other, TextRange):
|
|
136
|
+
return (self.start, self.end) > (other.start, other.end)
|
|
137
|
+
elif isinstance(other, TextPosition):
|
|
138
|
+
return (self.start, self.end) > (other, other)
|
|
139
|
+
return NotImplemented
|
|
140
|
+
|
|
141
|
+
def __ge__(self, other: Any) -> bool:
|
|
142
|
+
if isinstance(other, TextRange):
|
|
143
|
+
return (self.start, self.end) >= (other.start, other.end)
|
|
144
|
+
elif isinstance(other, TextPosition):
|
|
145
|
+
return (self.start, self.end) >= (other, other)
|
|
146
|
+
return NotImplemented
|
|
147
|
+
|
|
148
|
+
def to_lsp(self) -> types.Range:
|
|
149
|
+
return types.Range(start=self.start.to_lsp(), end=self.end.to_lsp())
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def chars_in_range(text: str, range: TextRange) -> str:
|
|
153
|
+
"""
|
|
154
|
+
Returns a substring of ``text`` containing all characters in the range described by ``range``.
|
|
155
|
+
|
|
156
|
+
If ``range`` is not contained within ``text``, an empty string is returned.
|
|
157
|
+
In general, this function is only intended to be used with ranges originally generated from ``text``.
|
|
158
|
+
:param text: The text document.
|
|
159
|
+
:param range: The range of characters to extract.
|
|
160
|
+
:return: Substring of ``text`` described by ``range``.
|
|
161
|
+
"""
|
|
162
|
+
lines = text.split('\n')
|
|
163
|
+
if range.end.line >= len(lines):
|
|
164
|
+
return ""
|
|
165
|
+
|
|
166
|
+
line_delta = range.end.line - range.start.line
|
|
167
|
+
|
|
168
|
+
if line_delta == 0:
|
|
169
|
+
return lines[range.start.line][range.start.offset:range.end.offset]
|
|
170
|
+
|
|
171
|
+
result: str = lines[range.start.line][range.start.offset:] + "\n"
|
|
172
|
+
if line_delta > 1:
|
|
173
|
+
result += str.join("\n", lines[range.start.line + 1:range.end.line]) + "\n"
|
|
174
|
+
result += lines[range.end.line][:range.end.offset]
|
|
175
|
+
return result
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class TokenType(enum.Enum):
|
|
179
|
+
TEXT = enum.auto()
|
|
180
|
+
WHITESPACE = enum.auto()
|
|
181
|
+
NEWLINE = enum.auto()
|
|
182
|
+
ELEMENT_DELIMITER = enum.auto()
|
|
183
|
+
PUNCTUATOR = enum.auto()
|
|
184
|
+
COMMENT = enum.auto()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
ELEMENTS_DELIMITERS: set[str] = {"{", "}", ","}
|
|
188
|
+
PUNCTUATORS: set[str] = {"=", ":", ";", "."}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
WHITESPACE_NO_NEWLINE = string.whitespace.replace("\n", "")
|
|
193
|
+
"""Whitespace characters without a newline"""
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class ZedscriptSource:
|
|
198
|
+
def __init__(self, text: str) -> None:
|
|
199
|
+
self.string: str = text
|
|
200
|
+
self.tokens: TokenCollection = TokenCollection()
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class Token:
|
|
204
|
+
def __init__(
|
|
205
|
+
self, type: TokenType, pos: TextPosition, end: TextPosition,
|
|
206
|
+
source: ZedscriptSource, text: str
|
|
207
|
+
) -> None:
|
|
208
|
+
self.type: TokenType = type
|
|
209
|
+
self.pos: TextPosition = pos
|
|
210
|
+
"""Start position of the token."""
|
|
211
|
+
self.end: TextPosition = end
|
|
212
|
+
"""End position of the token."""
|
|
213
|
+
self.source: ZedscriptSource = source
|
|
214
|
+
self.text = text
|
|
215
|
+
|
|
216
|
+
def pos_of(self, i: int) -> TextPosition:
|
|
217
|
+
"""
|
|
218
|
+
Returns the TextPosition of the character at index i in the string.
|
|
219
|
+
:param i: Index of the character.
|
|
220
|
+
:return: Position of the character.
|
|
221
|
+
"""
|
|
222
|
+
return TextPosition.from_index(self.text, i, self.pos)
|
|
223
|
+
|
|
224
|
+
# @deprecated("Use end property instead.")
|
|
225
|
+
def end_pos(self) -> TextPosition:
|
|
226
|
+
"""
|
|
227
|
+
Calculates the end position of the token.
|
|
228
|
+
The end position of a token is the same as the start position of the next token.
|
|
229
|
+
:return:
|
|
230
|
+
"""
|
|
231
|
+
return self.end
|
|
232
|
+
|
|
233
|
+
def __str__(self) -> str:
|
|
234
|
+
return self.text
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class TokenCollection(UserList[Token]):
|
|
238
|
+
def at(self, pos: TextPosition) -> Token | None:
|
|
239
|
+
for token in self.data:
|
|
240
|
+
if token.end > pos:
|
|
241
|
+
if token.pos < pos:
|
|
242
|
+
raise RuntimeError("pos is not contained within the collection")
|
|
243
|
+
return token
|
|
244
|
+
raise RuntimeError("pos is not contained within the collection")
|
|
245
|
+
|
|
246
|
+
def pos_of(self, i: int) -> TextPosition:
|
|
247
|
+
"""
|
|
248
|
+
Returns the TextPosition of the character at index ``i`` in the total string of the collection.
|
|
249
|
+
:param i: Character index.
|
|
250
|
+
:return: Position of the character.
|
|
251
|
+
"""
|
|
252
|
+
# FIXME: this is a naive implementation, as it assumes there are no gaps between tokens
|
|
253
|
+
# it is valid for a gap to exist when comments are involved
|
|
254
|
+
total_length: int = 0
|
|
255
|
+
|
|
256
|
+
if len(str(self)) == i:
|
|
257
|
+
return self.data[-1].end
|
|
258
|
+
|
|
259
|
+
token: Token | None = None
|
|
260
|
+
for token in self.data:
|
|
261
|
+
token_length = len(str(token))
|
|
262
|
+
if total_length + token_length > i:
|
|
263
|
+
break
|
|
264
|
+
total_length += token_length
|
|
265
|
+
assert token is not None
|
|
266
|
+
|
|
267
|
+
return token.pos_of(i - total_length)
|
|
268
|
+
|
|
269
|
+
def to_range(self) -> TextRange:
|
|
270
|
+
if not self.data:
|
|
271
|
+
return TextRange(TextPosition(0, 0), TextPosition(0, 0))
|
|
272
|
+
return TextRange(self.data[0].pos, self.data[-1].end)
|
|
273
|
+
|
|
274
|
+
def strip(self) -> TokenCollection:
|
|
275
|
+
# early return
|
|
276
|
+
end = len(self.data)
|
|
277
|
+
if end == 0:
|
|
278
|
+
return TokenCollection(self.data)
|
|
279
|
+
|
|
280
|
+
start: int = 0
|
|
281
|
+
while start < len(self.data):
|
|
282
|
+
if self.data[start].type is not TokenType.WHITESPACE:
|
|
283
|
+
break
|
|
284
|
+
start += 1
|
|
285
|
+
|
|
286
|
+
while end >= start:
|
|
287
|
+
if self.data[end - 1].type is not TokenType.WHITESPACE:
|
|
288
|
+
break
|
|
289
|
+
end -= 1
|
|
290
|
+
|
|
291
|
+
return TokenCollection(self.data[start:end])
|
|
292
|
+
|
|
293
|
+
def __str__(self) -> str:
|
|
294
|
+
return str.join("", [token.text for token in self.data])
|
|
295
|
+
|
|
296
|
+
def split(self, separator: str = ".") -> list['TokenCollection']:
|
|
297
|
+
assert separator in PUNCTUATORS, f"Separator '{separator}' is not a recognized punctuator. Only {PUNCTUATORS} are allowed."
|
|
298
|
+
|
|
299
|
+
result: list['TokenCollection'] = []
|
|
300
|
+
|
|
301
|
+
current_tokens: list[Token] = []
|
|
302
|
+
for token in self.data:
|
|
303
|
+
if token.text == separator:
|
|
304
|
+
if current_tokens:
|
|
305
|
+
result.append(TokenCollection(current_tokens))
|
|
306
|
+
current_tokens = []
|
|
307
|
+
else:
|
|
308
|
+
current_tokens.append(token)
|
|
309
|
+
if current_tokens:
|
|
310
|
+
result.append(TokenCollection(current_tokens))
|
|
311
|
+
|
|
312
|
+
return result
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
# TODO: this class is kinda redundant after all
|
|
316
|
+
class TokenBuilder:
|
|
317
|
+
def __init__(self, pos: TextPosition, type: TokenType, source: ZedscriptSource) -> None:
|
|
318
|
+
self.type: TokenType = type
|
|
319
|
+
self.pos: TextPosition = pos
|
|
320
|
+
self.text: str = ""
|
|
321
|
+
self.source: ZedscriptSource = source
|
|
322
|
+
|
|
323
|
+
def add(self, char: str) -> None:
|
|
324
|
+
self.text += char
|
|
325
|
+
|
|
326
|
+
def build(self, end: TextPosition) -> Token:
|
|
327
|
+
return Token(self.type, self.pos, end, self.source, self.text)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class Lexer:
|
|
331
|
+
def __init__(self, text: str) -> None:
|
|
332
|
+
self.text: str = text
|
|
333
|
+
self.source = ZedscriptSource(text)
|
|
334
|
+
self.pos: int = -1
|
|
335
|
+
self.line: int = 0
|
|
336
|
+
self.offset: int = 0
|
|
337
|
+
|
|
338
|
+
def has_next(self, num_characters: int = 1) -> bool:
|
|
339
|
+
return self.pos + num_characters < len(self.text)
|
|
340
|
+
|
|
341
|
+
def next(self) -> str:
|
|
342
|
+
assert self.has_next()
|
|
343
|
+
self.pos += 1
|
|
344
|
+
char: str = self.text[self.pos]
|
|
345
|
+
if char == "\n":
|
|
346
|
+
self.offset = 0
|
|
347
|
+
self.line += 1
|
|
348
|
+
else:
|
|
349
|
+
self.offset += 1
|
|
350
|
+
return char
|
|
351
|
+
|
|
352
|
+
def peek(self, num_characters: int = 1) -> str:
|
|
353
|
+
"""
|
|
354
|
+
Peek ahead in the text by the specified number of characters without advancing the current position.
|
|
355
|
+
`num_characters = 0` would be the current character.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
num_characters (int, optional): The number of characters to peek ahead. Defaults to 1.
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
str: The character at the specified lookahead position.
|
|
362
|
+
"""
|
|
363
|
+
assert self.pos + num_characters < len(self.text), f"Peek position out of range (pos: {self.pos}, num_characters: {num_characters}, len: {len(self.text)})"
|
|
364
|
+
return self.text[self.pos + num_characters]
|
|
365
|
+
|
|
366
|
+
def start_token(self, type: TokenType) -> TokenBuilder:
|
|
367
|
+
return TokenBuilder(TextPosition(self.line, self.offset), type, self.source)
|
|
368
|
+
|
|
369
|
+
def tokenize_comment(self) -> None:
|
|
370
|
+
assert self.check_comment()
|
|
371
|
+
|
|
372
|
+
token = self.start_token(TokenType.COMMENT)
|
|
373
|
+
# we already know the first two characters are comment indicators
|
|
374
|
+
token.add(self.next())
|
|
375
|
+
token.add(self.next())
|
|
376
|
+
|
|
377
|
+
while self.has_next():
|
|
378
|
+
char = self.next()
|
|
379
|
+
token.add(char)
|
|
380
|
+
if char == "*" and self.peek(1) == "/":
|
|
381
|
+
token.add(self.next())
|
|
382
|
+
break
|
|
383
|
+
|
|
384
|
+
self.source.tokens.append(
|
|
385
|
+
token.build(
|
|
386
|
+
TextPosition(self.line, self.offset)
|
|
387
|
+
)
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
def check_comment(self) -> bool:
|
|
391
|
+
"""True if the current position in the text indicates the start of a comment."""
|
|
392
|
+
return (self.peek(1) == "/"
|
|
393
|
+
and self.has_next(2)
|
|
394
|
+
and self.peek(2) == "*")
|
|
395
|
+
|
|
396
|
+
def tokenize_punctuator(self) -> None:
|
|
397
|
+
token = self.start_token(TokenType.PUNCTUATOR)
|
|
398
|
+
token.add(self.next())
|
|
399
|
+
self.source.tokens.append(
|
|
400
|
+
token.build(
|
|
401
|
+
TextPosition(self.line, self.offset)
|
|
402
|
+
)
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
def tokenize_text(self) -> None:
|
|
406
|
+
token = self.start_token(TokenType.TEXT)
|
|
407
|
+
|
|
408
|
+
while self.has_next():
|
|
409
|
+
char = self.peek()
|
|
410
|
+
if (self.check_comment()
|
|
411
|
+
or char in ELEMENTS_DELIMITERS
|
|
412
|
+
or char in string.whitespace
|
|
413
|
+
or char in PUNCTUATORS):
|
|
414
|
+
break
|
|
415
|
+
token.add(self.next())
|
|
416
|
+
|
|
417
|
+
self.source.tokens.append(
|
|
418
|
+
token.build(
|
|
419
|
+
TextPosition(self.line, self.offset)
|
|
420
|
+
)
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
def tokenize_whitespace(self) -> None:
|
|
424
|
+
token = self.start_token(TokenType.WHITESPACE)
|
|
425
|
+
|
|
426
|
+
while self.has_next():
|
|
427
|
+
char = self.peek()
|
|
428
|
+
if char not in string.whitespace:
|
|
429
|
+
break
|
|
430
|
+
token.add(self.next())
|
|
431
|
+
|
|
432
|
+
self.source.tokens.append(
|
|
433
|
+
token.build(
|
|
434
|
+
TextPosition(self.line, self.offset)
|
|
435
|
+
)
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
@staticmethod
|
|
439
|
+
def tokenize(raw: str) -> TokenCollection:
|
|
440
|
+
lexer: Lexer = Lexer(raw)
|
|
441
|
+
while lexer.has_next():
|
|
442
|
+
char = lexer.peek()
|
|
443
|
+
if lexer.check_comment():
|
|
444
|
+
lexer.tokenize_comment()
|
|
445
|
+
continue
|
|
446
|
+
elif char in PUNCTUATORS:
|
|
447
|
+
lexer.tokenize_punctuator()
|
|
448
|
+
continue
|
|
449
|
+
elif char in ELEMENTS_DELIMITERS:
|
|
450
|
+
token = lexer.start_token(TokenType.ELEMENT_DELIMITER)
|
|
451
|
+
token.add(lexer.next())
|
|
452
|
+
lexer.source.tokens.append(
|
|
453
|
+
token.build(
|
|
454
|
+
TextPosition(lexer.line, lexer.offset)
|
|
455
|
+
)
|
|
456
|
+
)
|
|
457
|
+
continue
|
|
458
|
+
elif char in string.whitespace:
|
|
459
|
+
lexer.tokenize_whitespace()
|
|
460
|
+
continue
|
|
461
|
+
lexer.tokenize_text()
|
|
462
|
+
|
|
463
|
+
return TokenCollection(lexer.source.tokens)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
if __name__ == "__main__":
|
|
467
|
+
from pathlib import Path
|
|
468
|
+
workspace = Path(__file__).parent.parent.parent.parent
|
|
469
|
+
file = workspace / "tests" / "scripts" / "food.txt"
|
|
470
|
+
raw = file.read_text()
|
|
471
|
+
tokens = Lexer.tokenize(raw)
|
|
472
|
+
for token in tokens:
|
|
473
|
+
print(str(token.type).ljust(25) + f'"{repr(str(token))}"' + f' ({token.pos}-{token.end})')
|
|
474
|
+
|
|
475
|
+
print()
|
|
476
|
+
|
|
477
|
+
tokens = Lexer.tokenize("Parameter = Base.Item")
|
|
478
|
+
splitted_tokens = tokens.split()
|
|
479
|
+
for i, split in enumerate(splitted_tokens):
|
|
480
|
+
print(f"Split {i}:")
|
|
481
|
+
for token in split:
|
|
482
|
+
print(str(token.type).ljust(25) + f'"{repr(str(token))}"' + f' ({token.pos}-{token.end})')
|