pyscript-programming-language 1.12.0__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.
Files changed (76) hide show
  1. pyscript/__init__.py +49 -0
  2. pyscript/__init__.pyi +96 -0
  3. pyscript/__main__.py +303 -0
  4. pyscript/core/__init__.py +61 -0
  5. pyscript/core/analyzer.py +531 -0
  6. pyscript/core/bases.py +2 -0
  7. pyscript/core/buffer.py +43 -0
  8. pyscript/core/cache.py +70 -0
  9. pyscript/core/checks.py +42 -0
  10. pyscript/core/constants.py +123 -0
  11. pyscript/core/context.py +63 -0
  12. pyscript/core/editor/__init__.py +15 -0
  13. pyscript/core/editor/bases.py +35 -0
  14. pyscript/core/editor/gui.py +144 -0
  15. pyscript/core/editor/terminal.py +175 -0
  16. pyscript/core/exceptions.py +123 -0
  17. pyscript/core/handlers.py +57 -0
  18. pyscript/core/highlight.py +552 -0
  19. pyscript/core/interpreter.py +1546 -0
  20. pyscript/core/lexer.py +863 -0
  21. pyscript/core/mapping.py +139 -0
  22. pyscript/core/nodes.py +663 -0
  23. pyscript/core/objects.py +213 -0
  24. pyscript/core/parser.py +2456 -0
  25. pyscript/core/position.py +114 -0
  26. pyscript/core/pysbuiltins.py +703 -0
  27. pyscript/core/results.py +186 -0
  28. pyscript/core/runner.py +363 -0
  29. pyscript/core/shell.py +287 -0
  30. pyscript/core/symtab.py +103 -0
  31. pyscript/core/token.py +25 -0
  32. pyscript/core/utils/__init__.py +27 -0
  33. pyscript/core/utils/ansi.py +127 -0
  34. pyscript/core/utils/debug.py +60 -0
  35. pyscript/core/utils/decorators.py +53 -0
  36. pyscript/core/utils/generic.py +46 -0
  37. pyscript/core/utils/jsdict.py +32 -0
  38. pyscript/core/utils/module.py +28 -0
  39. pyscript/core/utils/path.py +29 -0
  40. pyscript/core/utils/similarity.py +22 -0
  41. pyscript/core/utils/string.py +49 -0
  42. pyscript/core/version.py +120 -0
  43. pyscript/lib/__hello__.pys +7 -0
  44. pyscript/lib/ansi.pys +14 -0
  45. pyscript/lib/ast/__init__.pys +36 -0
  46. pyscript/lib/ast/ast_dump.py +433 -0
  47. pyscript/lib/ast/ast_literal_eval.py +80 -0
  48. pyscript/lib/ast/ast_unparse.py +540 -0
  49. pyscript/lib/ast/ast_walk.py +256 -0
  50. pyscript/lib/brainfuck.pys +190 -0
  51. pyscript/lib/dis.pys +7 -0
  52. pyscript/lib/explorer.pys +218 -0
  53. pyscript/lib/fpstimer/__init__.pys +6 -0
  54. pyscript/lib/fpstimer/py_fpstimer.py +54 -0
  55. pyscript/lib/getch.pys +28 -0
  56. pyscript/lib/inspect.pys +25 -0
  57. pyscript/lib/jsdict.pys +5 -0
  58. pyscript/lib/keyword.pys +2 -0
  59. pyscript/lib/opcode.pys +1 -0
  60. pyscript/lib/parser.pys +165 -0
  61. pyscript/lib/site.pys +55 -0
  62. pyscript/lib/symtable.pys +5 -0
  63. pyscript/lib/token.pys +12 -0
  64. pyscript/lib/tokenize/__init__.pys +14 -0
  65. pyscript/lib/tokenize/tok_untokenize.py +64 -0
  66. pyscript/other/.nomedia +0 -0
  67. pyscript/other/PyScript.ico +0 -0
  68. pyscript/other/copyright +2 -0
  69. pyscript/other/credits +2 -0
  70. pyscript/other/license +21 -0
  71. pyscript/site-packages/this.pys +19 -0
  72. pyscript/this.py +8 -0
  73. pyscript_programming_language-1.12.0.dist-info/METADATA +133 -0
  74. pyscript_programming_language-1.12.0.dist-info/RECORD +76 -0
  75. pyscript_programming_language-1.12.0.dist-info/WHEEL +5 -0
  76. pyscript_programming_language-1.12.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2456 @@
1
+ from .bases import Pys
2
+ from .checks import is_list, is_left_bracket, is_right_bracket
3
+ from .constants import TOKENS, DEFAULT, DICT_TO_JSDICT
4
+ from .context import PysContext
5
+ from .exceptions import PysTraceback
6
+ from .mapping import BRACKETS_MAP
7
+ from .nodes import *
8
+ from .position import PysPosition
9
+ from .results import PysParserResult
10
+ from .token import PysToken
11
+ from .utils.decorators import typechecked
12
+ from .utils.generic import setimuattr
13
+ from .utils.jsdict import jsdict
14
+
15
+ from types import MappingProxyType
16
+ from typing import Optional, Callable
17
+
18
+ SEQUENCES_MAP = MappingProxyType({
19
+ 'dict': (TOKENS['LEFT-CURLY'], PysDictionaryNode),
20
+ 'set': (TOKENS['LEFT-CURLY'], PysSetNode),
21
+ 'list': (TOKENS['LEFT-SQUARE'], PysListNode),
22
+ 'tuple': (TOKENS['LEFT-PARENTHESIS'], PysTupleNode)
23
+ })
24
+
25
+ class PysParser(Pys):
26
+
27
+ @typechecked
28
+ def __init__(
29
+ self,
30
+ tokens: tuple[PysToken, ...] | tuple[PysToken],
31
+ flags: int = DEFAULT,
32
+ parser_flags: int = DEFAULT,
33
+ context_parent: Optional[PysContext] = None,
34
+ context_parent_entry_position: Optional[PysPosition] = None
35
+ ) -> None:
36
+
37
+ self.tokens = tokens
38
+ self.flags = flags
39
+ self.parser_flags = parser_flags
40
+ self.context_parent = context_parent
41
+ self.context_parent_entry_position = context_parent_entry_position
42
+
43
+ @typechecked
44
+ def parse(
45
+ self,
46
+ function: Optional[Callable[[], PysParserResult]] = None
47
+ ) -> tuple[PysNode, None] | tuple[None, PysTraceback]:
48
+
49
+ self.token_index = 0
50
+ self.bracket_level = 0
51
+
52
+ self.update_current_token()
53
+
54
+ result = (function or self.statements)()
55
+
56
+ if not result.error:
57
+ if is_right_bracket(self.current_token.type):
58
+ result.failure(self.new_error(f"unmatched {chr(self.current_token.type)!r}"))
59
+ elif self.current_token.type != TOKENS['NULL']:
60
+ result.failure(self.new_error("invalid syntax"))
61
+
62
+ return result.node, result.error
63
+
64
+ def update_current_token(self):
65
+ if 0 <= self.token_index < len(self.tokens):
66
+ self.current_token = self.tokens[self.token_index]
67
+
68
+ def advance(self):
69
+ self.token_index += 1
70
+ self.update_current_token()
71
+
72
+ def reverse(self, amount=1):
73
+ self.token_index -= amount
74
+ self.update_current_token()
75
+
76
+ def new_error(self, message, position=None):
77
+ return PysTraceback(
78
+ SyntaxError(message),
79
+ PysContext(
80
+ file=self.current_token.position.file,
81
+ flags=self.flags,
82
+ parent=self.context_parent,
83
+ parent_entry_position=self.context_parent_entry_position
84
+ ),
85
+ position or self.current_token.position
86
+ )
87
+
88
+ def statements(self):
89
+ result = PysParserResult()
90
+ start = self.current_token.position.start
91
+
92
+ statements = []
93
+ more_statements = True
94
+ bracket_level = self.bracket_level
95
+
96
+ self.bracket_level = 0
97
+
98
+ while True:
99
+ advance_count = self.skip(result, TOKENS['NEWLINE'], TOKENS['SEMICOLON'])
100
+
101
+ if not more_statements:
102
+ if advance_count == 0:
103
+ break
104
+ more_statements = True
105
+
106
+ statement = result.try_register(self.statement())
107
+ if result.error:
108
+ return result
109
+
110
+ if statement:
111
+ statements.append(statement)
112
+ else:
113
+ self.reverse(result.to_reverse_count)
114
+
115
+ more_statements = False
116
+
117
+ self.bracket_level = bracket_level
118
+
119
+ return result.success(
120
+ PysStatementsNode(
121
+ statements,
122
+ PysPosition(
123
+ self.current_token.position.file,
124
+ start,
125
+ self.current_token.position.end
126
+ )
127
+ )
128
+ )
129
+
130
+ def statement(self):
131
+ if self.current_token.match(TOKENS['KEYWORD'], 'from'):
132
+ return self.from_statement()
133
+
134
+ elif self.current_token.match(TOKENS['KEYWORD'], 'import'):
135
+ return self.import_statement()
136
+
137
+ elif self.current_token.match(TOKENS['KEYWORD'], 'if'):
138
+ return self.if_statement()
139
+
140
+ elif self.current_token.match(TOKENS['KEYWORD'], 'switch'):
141
+ return self.switch_statement()
142
+
143
+ elif self.current_token.match(TOKENS['KEYWORD'], 'try'):
144
+ return self.try_statement()
145
+
146
+ elif self.current_token.match(TOKENS['KEYWORD'], 'with'):
147
+ return self.with_statement()
148
+
149
+ elif self.current_token.match(TOKENS['KEYWORD'], 'for'):
150
+ return self.for_statement()
151
+
152
+ elif self.current_token.match(TOKENS['KEYWORD'], 'while'):
153
+ return self.while_statement()
154
+
155
+ elif self.current_token.match(TOKENS['KEYWORD'], 'do'):
156
+ return self.do_while_statement()
157
+
158
+ elif self.current_token.match(TOKENS['KEYWORD'], 'repeat'):
159
+ return self.repeat_statement()
160
+
161
+ elif self.current_token.match(TOKENS['KEYWORD'], 'class'):
162
+ return self.class_statement()
163
+
164
+ elif self.current_token.match(TOKENS['KEYWORD'], 'return'):
165
+ return self.return_statement()
166
+
167
+ elif self.current_token.match(TOKENS['KEYWORD'], 'global'):
168
+ return self.global_statement()
169
+
170
+ elif self.current_token.match(TOKENS['KEYWORD'], 'del', 'delete'):
171
+ return self.del_statement()
172
+
173
+ elif self.current_token.match(TOKENS['KEYWORD'], 'raise', 'throw'):
174
+ return self.throw_statement()
175
+
176
+ elif self.current_token.match(TOKENS['KEYWORD'], 'assert'):
177
+ return self.assert_statement()
178
+
179
+ elif self.current_token.type == TOKENS['AT']:
180
+ return self.decorator()
181
+
182
+ elif self.current_token.match(TOKENS['KEYWORD'], 'continue'):
183
+ result = PysParserResult()
184
+ position = self.current_token.position
185
+
186
+ result.register_advancement()
187
+ self.advance()
188
+
189
+ return result.success(PysContinueNode(position))
190
+
191
+ elif self.current_token.match(TOKENS['KEYWORD'], 'break'):
192
+ result = PysParserResult()
193
+ position = self.current_token.position
194
+
195
+ result.register_advancement()
196
+ self.advance()
197
+
198
+ return result.success(PysBreakNode(position))
199
+
200
+ result = PysParserResult()
201
+
202
+ assignment_expression = result.register(self.assignment_statement())
203
+ if result.error:
204
+ return result.failure(self.new_error("expected an expression or statement"), fatal=False)
205
+
206
+ return result.success(assignment_expression)
207
+
208
+ def expression(self, function=None):
209
+ function = function or self.single_expression
210
+ result = PysParserResult()
211
+
212
+ node = result.register(function())
213
+ if result.error:
214
+ return result
215
+
216
+ if self.current_token.type == TOKENS['COMMA']:
217
+ elements = [node]
218
+
219
+ while self.current_token.type == TOKENS['COMMA']:
220
+ end = self.current_token.position.end
221
+ result.register_advancement()
222
+ self.advance()
223
+ self.skip_expression(result)
224
+
225
+ element = result.try_register(function())
226
+ if result.error:
227
+ return result
228
+
229
+ if element:
230
+ end = element.position.end
231
+ elements.append(element)
232
+ else:
233
+ self.reverse(result.to_reverse_count)
234
+ break
235
+
236
+ self.skip_expression(result)
237
+
238
+ node = PysTupleNode(
239
+ elements,
240
+ PysPosition(
241
+ self.current_token.position.file,
242
+ node.position.start,
243
+ end
244
+ )
245
+ )
246
+
247
+ return result.success(node)
248
+
249
+ def walrus(self):
250
+ result = PysParserResult()
251
+
252
+ node = result.register(self.single_expression())
253
+ if result.error:
254
+ return result
255
+
256
+ if self.current_token.type == TOKENS['EQUAL-COLON']:
257
+ operand = self.current_token
258
+
259
+ result.register_advancement()
260
+ self.advance()
261
+ self.skip_expression(result)
262
+
263
+ value = result.register(self.single_expression(), True)
264
+ if result.error:
265
+ return result
266
+
267
+ node = PysAssignmentNode(node, operand, value)
268
+
269
+ return result.success(node)
270
+
271
+ def single_expression(self):
272
+ if self.current_token.match(TOKENS['KEYWORD'], 'match'):
273
+ return self.match_expression()
274
+
275
+ elif self.current_token.match(TOKENS['KEYWORD'], 'def', 'define', 'func', 'function', 'constructor'):
276
+ return self.func_expression()
277
+
278
+ elif self.current_token.match(TOKENS['KEYWORD'], 'typeof'):
279
+ operand = self.current_token
280
+ result = PysParserResult()
281
+
282
+ result.register_advancement()
283
+ self.advance()
284
+ self.skip_expression(result)
285
+
286
+ node = result.register(self.single_expression(), True)
287
+ if result.error:
288
+ return result
289
+
290
+ return result.success(
291
+ PysUnaryOperatorNode(
292
+ operand,
293
+ node
294
+ )
295
+ )
296
+
297
+ return self.ternary()
298
+
299
+ def ternary(self):
300
+ result = PysParserResult()
301
+
302
+ node = result.register(self.nullish())
303
+ if result.error:
304
+ return result
305
+
306
+ if self.current_token.type == TOKENS['QUESTION']:
307
+ result.register_advancement()
308
+ self.advance()
309
+ self.skip_expression(result)
310
+
311
+ valid = result.register(self.ternary(), True)
312
+ if result.error:
313
+ return result
314
+
315
+ if self.current_token.type != TOKENS['COLON']:
316
+ return result.failure(self.new_error("expected ':'"))
317
+
318
+ result.register_advancement()
319
+ self.advance()
320
+ self.skip_expression(result)
321
+
322
+ invalid = result.register(self.ternary(), True)
323
+ if result.error:
324
+ return result
325
+
326
+ node = PysTernaryOperatorNode(
327
+ node,
328
+ valid,
329
+ invalid,
330
+ style='general'
331
+ )
332
+
333
+ elif self.current_token.match(TOKENS['KEYWORD'], 'if'):
334
+ result.register_advancement()
335
+ self.advance()
336
+ self.skip_expression(result)
337
+
338
+ condition = result.register(self.ternary(), True)
339
+ if result.error:
340
+ return result
341
+
342
+ if not self.current_token.match(TOKENS['KEYWORD'], 'else'):
343
+ return result.failure(self.new_error("expected 'else'"))
344
+
345
+ result.register_advancement()
346
+ self.advance()
347
+ self.skip_expression(result)
348
+
349
+ invalid = result.register(self.ternary(), True)
350
+ if result.error:
351
+ return result
352
+
353
+ node = PysTernaryOperatorNode(
354
+ condition,
355
+ node,
356
+ invalid,
357
+ style='pythonic'
358
+ )
359
+
360
+ return result.success(node)
361
+
362
+ def nullish(self):
363
+ return self.binary_operator(self.logic, TOKENS['DOUBLE-QUESTION'])
364
+
365
+ def logic(self):
366
+ return self.binary_operator(
367
+ self.member,
368
+ (TOKENS['KEYWORD'], 'and'),
369
+ (TOKENS['KEYWORD'], 'or'),
370
+ TOKENS['DOUBLE-AMPERSAND'], TOKENS['DOUBLE-PIPE']
371
+ )
372
+
373
+ def member(self):
374
+ return self.chain_operator(
375
+ self.comparison,
376
+ (TOKENS['KEYWORD'], 'in'),
377
+ (TOKENS['KEYWORD'], 'is'),
378
+ (TOKENS['KEYWORD'], 'not'),
379
+ TOKENS['MINUS-GREATER-THAN'], TOKENS['EXCLAMATION-GREATER-THAN'],
380
+ membership=True
381
+ )
382
+
383
+ def comparison(self):
384
+ token = self.current_token
385
+
386
+ if token.match(TOKENS['KEYWORD'], 'not') or token.type == TOKENS['EXCLAMATION']:
387
+ result = PysParserResult()
388
+
389
+ result.register_advancement()
390
+ self.advance()
391
+ self.skip_expression(result)
392
+
393
+ node = result.register(self.comparison(), True)
394
+ if result.error:
395
+ return result
396
+
397
+ return result.success(
398
+ PysUnaryOperatorNode(
399
+ token,
400
+ node
401
+ )
402
+ )
403
+
404
+ return self.chain_operator(
405
+ self.bitwise,
406
+ TOKENS['DOUBLE-EQUAL'], TOKENS['EQUAL-EXCLAMATION'], TOKENS['EQUAL-TILDE'], TOKENS['EXCLAMATION-TILDE'],
407
+ TOKENS['LESS-THAN'], TOKENS['GREATER-THAN'], TOKENS['EQUAL-LESS-THAN'], TOKENS['EQUAL-GREATER-THAN']
408
+ )
409
+
410
+ def bitwise(self):
411
+ return self.binary_operator(
412
+ self.arithmetic,
413
+ TOKENS['AMPERSAND'], TOKENS['PIPE'], TOKENS['CIRCUMFLEX'], TOKENS['DOUBLE-LESS-THAN'],
414
+ TOKENS['DOUBLE-GREATER-THAN']
415
+ )
416
+
417
+ def arithmetic(self):
418
+ return self.binary_operator(self.term, TOKENS['PLUS'], TOKENS['MINUS'])
419
+
420
+ def term(self):
421
+ return self.binary_operator(
422
+ self.factor,
423
+ TOKENS['STAR'], TOKENS['SLASH'], TOKENS['DOUBLE-SLASH'], TOKENS['PERCENT'], TOKENS['AT']
424
+ )
425
+
426
+ def factor(self):
427
+ token = self.current_token
428
+
429
+ if token.type in (TOKENS['PLUS'], TOKENS['MINUS'], TOKENS['TILDE']):
430
+ result = PysParserResult()
431
+
432
+ result.register_advancement()
433
+ self.advance()
434
+ self.skip_expression(result)
435
+
436
+ node = result.register(self.factor(), True)
437
+ if result.error:
438
+ return result
439
+
440
+ return result.success(
441
+ PysUnaryOperatorNode(
442
+ token,
443
+ node
444
+ )
445
+ )
446
+
447
+ return self.power()
448
+
449
+ def power(self):
450
+ result = PysParserResult()
451
+
452
+ left = result.register(self.incremental())
453
+ if result.error:
454
+ return result
455
+
456
+ if self.current_token.type == TOKENS['DOUBLE-STAR']:
457
+ operand = self.current_token
458
+
459
+ result.register_advancement()
460
+ self.advance()
461
+ self.skip_expression(result)
462
+
463
+ right = result.register(self.factor(), True)
464
+ if result.error:
465
+ return result
466
+
467
+ left = PysBinaryOperatorNode(left, operand, right)
468
+
469
+ return result.success(left)
470
+
471
+ def incremental(self):
472
+ result = PysParserResult()
473
+ token = self.current_token
474
+
475
+ if token.type in (TOKENS['DOUBLE-PLUS'], TOKENS['DOUBLE-MINUS']):
476
+ result.register_advancement()
477
+ self.advance()
478
+ self.skip_expression(result)
479
+
480
+ node = result.register(self.primary())
481
+ if result.error:
482
+ return result
483
+
484
+ return result.success(
485
+ PysIncrementalNode(
486
+ token,
487
+ node,
488
+ operand_position='left'
489
+ )
490
+ )
491
+
492
+ node = result.register(self.primary())
493
+ if result.error:
494
+ return result
495
+
496
+ if self.current_token.type in (TOKENS['DOUBLE-PLUS'], TOKENS['DOUBLE-MINUS']):
497
+ operand = self.current_token
498
+
499
+ result.register_advancement()
500
+ self.advance()
501
+ self.skip_expression(result)
502
+
503
+ node = PysIncrementalNode(
504
+ operand,
505
+ node,
506
+ operand_position='right'
507
+ )
508
+
509
+ return result.success(node)
510
+
511
+ def primary(self):
512
+ result = PysParserResult()
513
+ start = self.current_token.position.start
514
+
515
+ node = result.register(self.atom())
516
+ if result.error:
517
+ return result
518
+
519
+ while True:
520
+
521
+ if self.current_token.type == TOKENS['LEFT-PARENTHESIS']:
522
+ left_bracket_token = self.current_token
523
+ self.bracket_level += 1
524
+
525
+ result.register_advancement()
526
+ self.advance()
527
+ self.skip(result)
528
+
529
+ seen_keyword_argument = False
530
+ arguments = []
531
+
532
+ while not is_right_bracket(self.current_token.type):
533
+
534
+ argument_or_keyword = result.register(self.walrus(), True)
535
+ if result.error:
536
+ return result
537
+
538
+ if self.current_token.type == TOKENS['EQUAL']:
539
+ if not isinstance(argument_or_keyword, PysIdentifierNode):
540
+ return result.failure(
541
+ self.new_error("expected identifier (before '=')", argument_or_keyword.position)
542
+ )
543
+
544
+ result.register_advancement()
545
+ self.advance()
546
+ self.skip(result)
547
+ seen_keyword_argument = True
548
+
549
+ elif seen_keyword_argument:
550
+ return result.failure(self.new_error("expected '=' (follows keyword argument)"))
551
+
552
+ if seen_keyword_argument:
553
+ value = result.register(self.single_expression(), True)
554
+ if result.error:
555
+ return result
556
+ arguments.append((argument_or_keyword.name, value))
557
+ else:
558
+ arguments.append(argument_or_keyword)
559
+
560
+ self.skip(result)
561
+
562
+ if self.current_token.type == TOKENS['COMMA']:
563
+ result.register_advancement()
564
+ self.advance()
565
+ self.skip(result)
566
+
567
+ elif not is_right_bracket(self.current_token.type):
568
+ return result.failure(self.new_error("invalid syntax. Perhaps you forgot a comma?"))
569
+
570
+ end = self.current_token.position.end
571
+ self.close_bracket(result, left_bracket_token)
572
+ if result.error:
573
+ return result
574
+
575
+ self.bracket_level -= 1
576
+ self.skip_expression(result)
577
+
578
+ node = PysCallNode(
579
+ node,
580
+ arguments,
581
+ PysPosition(
582
+ self.current_token.position.file,
583
+ start,
584
+ end
585
+ )
586
+ )
587
+
588
+ elif self.current_token.type == TOKENS['LEFT-SQUARE']:
589
+ left_bracket_token = self.current_token
590
+ self.bracket_level += 1
591
+
592
+ index = 0
593
+ slices = []
594
+ indices = [None, None, None]
595
+ single_slice = True
596
+
597
+ result.register_advancement()
598
+ self.advance()
599
+ self.skip(result)
600
+
601
+ if self.current_token.type != TOKENS['COLON']:
602
+ indices[0] = result.register(self.walrus(), True)
603
+ if result.error:
604
+ return result
605
+
606
+ if self.current_token.type == TOKENS['COMMA']:
607
+ result.register_advancement()
608
+ self.advance()
609
+ self.skip(result)
610
+ single_slice = False
611
+
612
+ if not single_slice or is_right_bracket(self.current_token.type):
613
+ slices.append(indices[0])
614
+ indices = [None, None, None]
615
+
616
+ while not is_right_bracket(self.current_token.type):
617
+
618
+ if self.current_token.type != TOKENS['COLON']:
619
+ indices[index] = result.register(self.walrus(), True)
620
+ if result.error:
621
+ return result
622
+
623
+ index += 1
624
+ single_index = self.current_token.type != TOKENS['COLON']
625
+
626
+ while index < 3 and self.current_token.type == TOKENS['COLON']:
627
+ result.register_advancement()
628
+ self.advance()
629
+ self.skip(result)
630
+
631
+ if is_right_bracket(self.current_token.type):
632
+ break
633
+
634
+ indices[index] = result.try_register(self.walrus())
635
+ if result.error:
636
+ return result
637
+
638
+ self.skip(result)
639
+ index += 1
640
+
641
+ if single_index:
642
+ slices.append(indices[0])
643
+ else:
644
+ slices.append(slice(indices[0], indices[1], indices[2]))
645
+
646
+ indices = [None, None, None]
647
+ index = 0
648
+
649
+ if self.current_token.type == TOKENS['COMMA']:
650
+ result.register_advancement()
651
+ self.advance()
652
+ self.skip(result)
653
+ single_slice = False
654
+
655
+ elif not is_right_bracket(self.current_token.type):
656
+ return result.failure(self.new_error("invalid syntax. Perhaps you forgot a comma?"))
657
+
658
+ end = self.current_token.position.end
659
+ self.close_bracket(result, left_bracket_token)
660
+ if result.error:
661
+ return result
662
+
663
+ self.bracket_level -= 1
664
+ self.skip_expression(result)
665
+
666
+ if single_slice:
667
+ slices = slices[0]
668
+
669
+ node = PysSubscriptNode(
670
+ node,
671
+ slices,
672
+ PysPosition(
673
+ self.current_token.position.file,
674
+ start,
675
+ end
676
+ )
677
+ )
678
+
679
+ elif self.current_token.type == TOKENS['DOT']:
680
+ result.register_advancement()
681
+ self.advance()
682
+ self.skip_expression(result)
683
+
684
+ attribute = self.current_token
685
+
686
+ if attribute.type != TOKENS['IDENTIFIER']:
687
+ return result.failure(self.new_error("expected identifier"))
688
+
689
+ result.register_advancement()
690
+ self.advance()
691
+ self.skip_expression(result)
692
+
693
+ node = PysAttributeNode(node, attribute)
694
+
695
+ else:
696
+ break
697
+
698
+ return result.success(node)
699
+
700
+ def atom(self):
701
+ result = PysParserResult()
702
+ token = self.current_token
703
+
704
+ if token.match(TOKENS['KEYWORD'], '__debug__', 'True', 'False', 'None', 'true', 'false', 'nil', 'none', 'null'):
705
+ result.register_advancement()
706
+ self.advance()
707
+ self.skip_expression(result)
708
+
709
+ return result.success(PysKeywordNode(token))
710
+
711
+ elif token.type == TOKENS['IDENTIFIER']:
712
+ result.register_advancement()
713
+ self.advance()
714
+ self.skip_expression(result)
715
+
716
+ return result.success(PysIdentifierNode(token))
717
+
718
+ elif token.type == TOKENS['NUMBER']:
719
+ result.register_advancement()
720
+ self.advance()
721
+ self.skip_expression(result)
722
+
723
+ return result.success(PysNumberNode(token))
724
+
725
+ elif token.type == TOKENS['STRING']:
726
+ format = type(token.value)
727
+ string = '' if format is str else b''
728
+
729
+ while self.current_token.type == TOKENS['STRING']:
730
+
731
+ if not isinstance(self.current_token.value, format):
732
+ return result.failure(
733
+ self.new_error(
734
+ "cannot mix bytes and nonbytes literals",
735
+ self.current_token.position
736
+ )
737
+ )
738
+
739
+ string += self.current_token.value
740
+ end = self.current_token.position.end
741
+
742
+ result.register_advancement()
743
+ self.advance()
744
+ self.skip_expression(result)
745
+
746
+ return result.success(
747
+ PysStringNode(
748
+ PysToken(
749
+ TOKENS['STRING'],
750
+ PysPosition(
751
+ self.current_token.position.file,
752
+ token.position.start,
753
+ end
754
+ ),
755
+ string
756
+ )
757
+ )
758
+ )
759
+
760
+ elif token.type == TOKENS['LEFT-PARENTHESIS']:
761
+ return self.sequence_expression('tuple')
762
+
763
+ elif token.type == TOKENS['LEFT-SQUARE']:
764
+ return self.sequence_expression('list')
765
+
766
+ elif token.type == TOKENS['LEFT-CURLY']:
767
+ dict_expression = result.try_register(self.sequence_expression('dict'))
768
+ if result.error:
769
+ return result
770
+
771
+ if not dict_expression:
772
+ self.reverse(result.to_reverse_count)
773
+ return self.sequence_expression('set')
774
+
775
+ return result.success(dict_expression)
776
+
777
+ elif token.type == TOKENS['TRIPLE-DOT']:
778
+ result.register_advancement()
779
+ self.advance()
780
+ self.skip_expression(result)
781
+
782
+ return result.success(PysEllipsisNode(token.position))
783
+
784
+ return result.failure(self.new_error("expected expression"), fatal=False)
785
+
786
+ def sequence_expression(self, type, should_sequence=False):
787
+ result = PysParserResult()
788
+ start = self.current_token.position.start
789
+ left_bracket, node = SEQUENCES_MAP[type]
790
+
791
+ if self.current_token.type != left_bracket:
792
+ return result.failure(self.new_error(f"expected {chr(left_bracket)!r}"))
793
+
794
+ left_bracket_token = self.current_token
795
+ self.bracket_level += 1
796
+
797
+ result.register_advancement()
798
+ self.advance()
799
+ self.skip(result)
800
+
801
+ elements = []
802
+
803
+ if type == 'dict':
804
+ dict_to_jsdict = self.parser_flags & DICT_TO_JSDICT
805
+ always_dict = False
806
+
807
+ while not is_right_bracket(self.current_token.type):
808
+ if dict_to_jsdict:
809
+
810
+ if self.current_token.type == TOKENS['LEFT-SQUARE']:
811
+ left_square_token = self.current_token
812
+ result.register_advancement()
813
+ self.advance()
814
+ self.skip(result)
815
+
816
+ key = result.register(self.walrus(), True)
817
+ if result.error:
818
+ return result
819
+
820
+ self.close_bracket(result, left_square_token)
821
+ if result.error:
822
+ return result
823
+
824
+ elif self.current_token.type == TOKENS['IDENTIFIER']:
825
+ key = PysStringNode(self.current_token)
826
+ result.register_advancement()
827
+ self.advance()
828
+ self.skip(result)
829
+
830
+ else:
831
+ key = result.register(self.single_expression(), True)
832
+ if result.error:
833
+ return result
834
+
835
+ else:
836
+ key = result.register(self.walrus(), True)
837
+ if result.error:
838
+ return result
839
+
840
+ if self.current_token.type not in (TOKENS['COLON'], TOKENS['EQUAL']):
841
+ if not always_dict:
842
+ self.bracket_level -= 1
843
+ return result.failure(self.new_error("expected ':' or '='"), fatal=always_dict)
844
+
845
+ result.register_advancement()
846
+ self.advance()
847
+ self.skip(result)
848
+
849
+ value = result.register(self.walrus(), True)
850
+ if result.error:
851
+ return result
852
+
853
+ elements.append((key, value))
854
+ always_dict = True
855
+
856
+ if self.current_token.type == TOKENS['COMMA']:
857
+ result.register_advancement()
858
+ self.advance()
859
+ self.skip(result)
860
+
861
+ elif not is_right_bracket(self.current_token.type):
862
+ return result.failure(self.new_error("invalid syntax. Perhaps you forgot a comma?"))
863
+
864
+ else:
865
+
866
+ while not is_right_bracket(self.current_token.type):
867
+ elements.append(result.register(self.walrus(), True))
868
+ if result.error:
869
+ return result
870
+
871
+ self.skip(result)
872
+
873
+ if self.current_token.type == TOKENS['COMMA']:
874
+ result.register_advancement()
875
+ self.advance()
876
+ self.skip(result)
877
+ should_sequence = True
878
+
879
+ elif not is_right_bracket(self.current_token.type):
880
+ return result.failure(self.new_error("invalid syntax. Perhaps you forgot a comma?"))
881
+
882
+ end = self.current_token.position.end
883
+ self.close_bracket(result, left_bracket_token)
884
+ if result.error:
885
+ return result
886
+
887
+ position = PysPosition(self.current_token.position.file, start, end)
888
+ self.bracket_level -= 1
889
+ self.skip_expression(result)
890
+
891
+ if type == 'tuple' and not should_sequence and elements:
892
+ element = elements[0]
893
+ setimuattr(element, 'position', position)
894
+ return result.success(element)
895
+
896
+ elif type == 'dict':
897
+ return result.success(
898
+ node(
899
+ pairs=elements,
900
+ class_type=jsdict if dict_to_jsdict else dict,
901
+ position=position
902
+ )
903
+ )
904
+
905
+ return result.success(node(elements, position))
906
+
907
+ def assignment_statement(self, func=None):
908
+ result = PysParserResult()
909
+
910
+ node = result.register(self.expression(func))
911
+ if result.error:
912
+ return result
913
+
914
+ if self.current_token.type in (
915
+ TOKENS['EQUAL'],
916
+ TOKENS['EQUAL-PLUS'],
917
+ TOKENS['EQUAL-MINUS'],
918
+ TOKENS['EQUAL-STAR'],
919
+ TOKENS['EQUAL-SLASH'],
920
+ TOKENS['EQUAL-DOUBLE-SLASH'],
921
+ TOKENS['EQUAL-PERCENT'],
922
+ TOKENS['EQUAL-AT'],
923
+ TOKENS['EQUAL-DOUBLE-STAR'],
924
+ TOKENS['EQUAL-AMPERSAND'],
925
+ TOKENS['EQUAL-PIPE'],
926
+ TOKENS['EQUAL-CIRCUMFLEX'],
927
+ TOKENS['EQUAL-DOUBLE-LESS-THAN'],
928
+ TOKENS['EQUAL-DOUBLE-GREATER-THAN']
929
+ ):
930
+ operand = self.current_token
931
+
932
+ result.register_advancement()
933
+ self.advance()
934
+ self.skip_expression(result)
935
+
936
+ value = result.register(self.assignment_statement(func), True)
937
+ if result.error:
938
+ return result
939
+
940
+ node = PysAssignmentNode(node, operand, value)
941
+
942
+ return result.success(node)
943
+
944
+ def from_statement(self):
945
+ result = PysParserResult()
946
+ position = self.current_token.position
947
+
948
+ if not self.current_token.match(TOKENS['KEYWORD'], 'from'):
949
+ return result.failure(self.new_error("expected 'from'"))
950
+
951
+ result.register_advancement()
952
+ self.advance()
953
+ self.skip(result)
954
+
955
+ if self.current_token.type not in (TOKENS['STRING'], TOKENS['IDENTIFIER']):
956
+ return result.failure(self.new_error("expected string or identifier"))
957
+
958
+ name = self.current_token
959
+
960
+ result.register_advancement()
961
+ self.advance()
962
+ self.skip(result)
963
+
964
+ if not self.current_token.match(TOKENS['KEYWORD'], 'import'):
965
+ return result.failure(self.new_error("expected 'import'"))
966
+
967
+ result.register_advancement()
968
+ self.advance()
969
+ self.skip(result)
970
+
971
+ if self.current_token.type == TOKENS['STAR']:
972
+ result.register_advancement()
973
+ self.advance()
974
+ packages = 'all'
975
+
976
+ else:
977
+ bracket = False
978
+ packages = []
979
+
980
+ if self.current_token.type == TOKENS['LEFT-PARENTHESIS']:
981
+ bracket = True
982
+ left_bracket_token = self.current_token
983
+ self.bracket_level += 1
984
+
985
+ result.register_advancement()
986
+ self.advance()
987
+ self.skip(result)
988
+
989
+ elif is_left_bracket(self.current_token.type):
990
+ return result.failure(self.new_error(f"expected '(' not {chr(self.current_token.type)!r}"))
991
+
992
+ if self.current_token.type != TOKENS['IDENTIFIER']:
993
+ return result.failure(self.new_error("expected identifier"))
994
+
995
+ while True:
996
+ package = self.current_token
997
+ as_package = None
998
+ processed = False
999
+
1000
+ if name.value == '__future__':
1001
+ processed = result.register(self.proccess_future(package.value))
1002
+ if result.error:
1003
+ return result
1004
+
1005
+ result.register_advancement()
1006
+ self.advance()
1007
+ self.skip_expression(result)
1008
+
1009
+ if self.current_token.match(TOKENS['KEYWORD'], 'as'):
1010
+ result.register_advancement()
1011
+ self.advance()
1012
+ self.skip_expression(result)
1013
+
1014
+ if self.current_token.type != TOKENS['IDENTIFIER']:
1015
+ return result.failure(self.new_error("expected identifier"))
1016
+
1017
+ as_package = self.current_token
1018
+
1019
+ result.register_advancement()
1020
+ self.advance()
1021
+ self.skip_expression(result)
1022
+
1023
+ if not processed:
1024
+ packages.append((package, as_package))
1025
+
1026
+ if self.current_token.type == TOKENS['COMMA']:
1027
+ result.register_advancement()
1028
+ self.advance()
1029
+ self.skip_expression(result)
1030
+
1031
+ elif bracket and not is_right_bracket(self.current_token.type):
1032
+ return result.failure(self.new_error("invalid syntax. Perhaps you forgot a comma?"))
1033
+
1034
+ else:
1035
+ break
1036
+
1037
+ if bracket:
1038
+ self.close_bracket(result, left_bracket_token)
1039
+ if result.error:
1040
+ return result
1041
+
1042
+ self.bracket_level -= 1
1043
+
1044
+ return result.success(
1045
+ PysImportNode(
1046
+ (name, None),
1047
+ packages,
1048
+ position
1049
+ )
1050
+ )
1051
+
1052
+ def import_statement(self):
1053
+ result = PysParserResult()
1054
+ position = self.current_token.position
1055
+
1056
+ if not self.current_token.match(TOKENS['KEYWORD'], 'import'):
1057
+ return result.failure(self.new_error("expected 'import'"))
1058
+
1059
+ result.register_advancement()
1060
+ self.advance()
1061
+ self.skip(result)
1062
+
1063
+ if self.current_token.type not in (TOKENS['STRING'], TOKENS['IDENTIFIER']):
1064
+ return result.failure(self.new_error("expected string or identifier"))
1065
+
1066
+ name = self.current_token
1067
+ as_name = None
1068
+
1069
+ result.register_advancement()
1070
+ self.advance()
1071
+ advance_count = self.skip(result)
1072
+
1073
+ if self.current_token.match(TOKENS['KEYWORD'], 'as'):
1074
+ result.register_advancement()
1075
+ self.advance()
1076
+ self.skip(result)
1077
+
1078
+ if self.current_token.type != TOKENS['IDENTIFIER']:
1079
+ return result.failure(self.new_error("expected identifier"))
1080
+
1081
+ as_name = self.current_token
1082
+ result.register_advancement()
1083
+ self.advance()
1084
+
1085
+ else:
1086
+ self.reverse(advance_count)
1087
+
1088
+ return result.success(
1089
+ PysImportNode(
1090
+ (name, as_name),
1091
+ [],
1092
+ position
1093
+ )
1094
+ )
1095
+
1096
+ def if_statement(self):
1097
+ result = PysParserResult()
1098
+ position = self.current_token.position
1099
+
1100
+ if not self.current_token.match(TOKENS['KEYWORD'], 'if'):
1101
+ return result.failure(self.new_error("expected 'if'"))
1102
+
1103
+ result.register_advancement()
1104
+ self.advance()
1105
+ self.skip(result)
1106
+
1107
+ condition = result.register(self.walrus(), True)
1108
+ if result.error:
1109
+ return result
1110
+
1111
+ self.skip(result)
1112
+
1113
+ body = result.register(self.block_statements(), True)
1114
+ if result.error:
1115
+ return result
1116
+
1117
+ cases = [(condition, body)]
1118
+ else_body = None
1119
+ advance_count = self.skip(result)
1120
+
1121
+ while True:
1122
+
1123
+ if self.current_token.match(TOKENS['KEYWORD'], 'elif', 'elseif'):
1124
+ result.register_advancement()
1125
+ self.advance()
1126
+ self.skip(result)
1127
+ conditional_chain = True
1128
+
1129
+ elif self.current_token.match(TOKENS['KEYWORD'], 'else'):
1130
+ result.register_advancement()
1131
+ self.advance()
1132
+ self.skip(result)
1133
+
1134
+ if self.current_token.match(TOKENS['KEYWORD'], 'if'):
1135
+ result.register_advancement()
1136
+ self.advance()
1137
+ self.skip(result)
1138
+ conditional_chain = True
1139
+
1140
+ else:
1141
+ else_body = result.register(self.block_statements(), True)
1142
+ if result.error:
1143
+ return result
1144
+
1145
+ advance_count = 0
1146
+ break
1147
+
1148
+ else:
1149
+ break
1150
+
1151
+ if conditional_chain:
1152
+ conditional_chain = False
1153
+
1154
+ condition = result.register(self.walrus(), True)
1155
+ if result.error:
1156
+ return result
1157
+
1158
+ self.skip(result)
1159
+
1160
+ body = result.register(self.block_statements(), True)
1161
+ if result.error:
1162
+ return result
1163
+
1164
+ cases.append((condition, body))
1165
+ advance_count = self.skip(result)
1166
+
1167
+ self.reverse(advance_count)
1168
+
1169
+ return result.success(
1170
+ PysIfNode(
1171
+ cases,
1172
+ else_body,
1173
+ position
1174
+ )
1175
+ )
1176
+
1177
+ def switch_statement(self):
1178
+ result = PysParserResult()
1179
+ position = self.current_token.position
1180
+
1181
+ if not self.current_token.match(TOKENS['KEYWORD'], 'switch'):
1182
+ return result.failure(self.new_error("expected 'switch'"))
1183
+
1184
+ result.register_advancement()
1185
+ self.advance()
1186
+ self.skip(result)
1187
+
1188
+ target = result.register(self.walrus(), True)
1189
+ if result.error:
1190
+ return result
1191
+
1192
+ self.skip(result)
1193
+
1194
+ if self.current_token.type != TOKENS['LEFT-CURLY']:
1195
+ return result.failure(self.new_error("expected '{'"))
1196
+
1197
+ left_bracket_token = self.current_token
1198
+
1199
+ result.register_advancement()
1200
+ self.advance()
1201
+ self.skip(result)
1202
+
1203
+ cases = []
1204
+ default_body = None
1205
+
1206
+ while True:
1207
+
1208
+ if self.current_token.match(TOKENS['KEYWORD'], 'case'):
1209
+ result.register_advancement()
1210
+ self.advance()
1211
+ self.skip(result)
1212
+
1213
+ case = result.register(self.walrus(), True)
1214
+ if result.error:
1215
+ return result
1216
+
1217
+ self.skip(result)
1218
+
1219
+ if self.current_token.type != TOKENS['COLON']:
1220
+ return result.failure(self.new_error("expected ':'"))
1221
+
1222
+ result.register_advancement()
1223
+ self.advance()
1224
+
1225
+ body = result.register(self.statements())
1226
+ if result.error:
1227
+ return result
1228
+
1229
+ cases.append((case, body))
1230
+
1231
+ elif self.current_token.match(TOKENS['KEYWORD'], 'default'):
1232
+ result.register_advancement()
1233
+ self.advance()
1234
+ self.skip(result)
1235
+
1236
+ if self.current_token.type != TOKENS['COLON']:
1237
+ return result.failure(self.new_error("expected ':'"))
1238
+
1239
+ result.register_advancement()
1240
+ self.advance()
1241
+
1242
+ default_body = result.register(self.statements())
1243
+ if result.error:
1244
+ return result
1245
+
1246
+ break
1247
+
1248
+ else:
1249
+ break
1250
+
1251
+ self.close_bracket(result, left_bracket_token)
1252
+ if result.error:
1253
+ return result
1254
+
1255
+ return result.success(
1256
+ PysSwitchNode(
1257
+ target,
1258
+ cases,
1259
+ default_body,
1260
+ position
1261
+ )
1262
+ )
1263
+
1264
+ def match_expression(self):
1265
+ result = PysParserResult()
1266
+ position = self.current_token.position
1267
+
1268
+ if not self.current_token.match(TOKENS['KEYWORD'], 'match'):
1269
+ return result.failure(self.new_error("expected 'match'"))
1270
+
1271
+ result.register_advancement()
1272
+ self.advance()
1273
+ self.skip(result)
1274
+
1275
+ target = None
1276
+
1277
+ if self.current_token.type != TOKENS['LEFT-CURLY']:
1278
+ target = result.register(self.walrus(), True)
1279
+ if result.error:
1280
+ return result.failure(self.new_error("expected expression or '{'"))
1281
+
1282
+ self.skip(result)
1283
+
1284
+ if self.current_token.type != TOKENS['LEFT-CURLY']:
1285
+ return result.failure(self.new_error("expected '{'"))
1286
+
1287
+ left_bracket_token = self.current_token
1288
+ self.bracket_level += 1
1289
+
1290
+ result.register_advancement()
1291
+ self.advance()
1292
+ self.skip(result)
1293
+
1294
+ cases = []
1295
+ default = None
1296
+
1297
+ while not is_right_bracket(self.current_token.type):
1298
+
1299
+ if self.current_token.match(TOKENS['KEYWORD'], 'default'):
1300
+ result.register_advancement()
1301
+ self.advance()
1302
+ self.skip(result)
1303
+
1304
+ if self.current_token.type != TOKENS['COLON']:
1305
+ return result.failure(self.new_error("expected ':'"))
1306
+
1307
+ result.register_advancement()
1308
+ self.advance()
1309
+ self.skip(result)
1310
+
1311
+ default = result.register(self.single_expression(), True)
1312
+ if result.error:
1313
+ return result
1314
+
1315
+ break
1316
+
1317
+ condition = result.register(self.single_expression(), True)
1318
+ if result.error:
1319
+ return result
1320
+
1321
+ if self.current_token.type != TOKENS['COLON']:
1322
+ return result.failure(self.new_error("expected ':'"))
1323
+
1324
+ result.register_advancement()
1325
+ self.advance()
1326
+ self.skip(result)
1327
+
1328
+ value = result.register(self.single_expression(), True)
1329
+ if result.error:
1330
+ return result
1331
+
1332
+ cases.append((condition, value))
1333
+
1334
+ if self.current_token.type == TOKENS['COMMA']:
1335
+ result.register_advancement()
1336
+ self.advance()
1337
+ self.skip(result)
1338
+
1339
+ elif not is_right_bracket(self.current_token.type):
1340
+ return result.failure(self.new_error("invalid syntax. Perhaps you forgot a comma?"))
1341
+
1342
+ self.close_bracket(result, left_bracket_token)
1343
+ if result.error:
1344
+ return result
1345
+
1346
+ self.bracket_level -= 1
1347
+ self.skip_expression(result)
1348
+
1349
+ return result.success(
1350
+ PysMatchNode(
1351
+ target,
1352
+ cases,
1353
+ default,
1354
+ position
1355
+ )
1356
+ )
1357
+
1358
+ def try_statement(self):
1359
+ result = PysParserResult()
1360
+ position = self.current_token.position
1361
+
1362
+ if not self.current_token.match(TOKENS['KEYWORD'], 'try'):
1363
+ return result.failure(self.new_error("expected 'try'"))
1364
+
1365
+ result.register_advancement()
1366
+ self.advance()
1367
+ self.skip(result)
1368
+
1369
+ body = result.register(self.block_statements(), True)
1370
+ if result.error:
1371
+ return result
1372
+
1373
+ catch_cases = []
1374
+ else_body = None
1375
+ finally_body = None
1376
+ advance_count = self.skip(result)
1377
+
1378
+ if self.current_token.match(TOKENS['KEYWORD'], 'catch', 'except'):
1379
+ all_catch_handler = False
1380
+
1381
+ while self.current_token.match(TOKENS['KEYWORD'], 'catch', 'except'):
1382
+ if all_catch_handler:
1383
+ return result.failure(self.new_error("only one catch-all except clause allowed"))
1384
+
1385
+ result.register_advancement()
1386
+ self.advance()
1387
+ self.skip(result)
1388
+
1389
+ bracket = False
1390
+ targets = []
1391
+ parameter = None
1392
+
1393
+ if self.current_token.type == TOKENS['LEFT-PARENTHESIS']:
1394
+ bracket = True
1395
+ left_bracket_token = self.current_token
1396
+ self.bracket_level += 1
1397
+
1398
+ result.register_advancement()
1399
+ self.advance()
1400
+ self.skip(result)
1401
+
1402
+ if self.current_token.type != TOKENS['IDENTIFIER']:
1403
+ return result.failure(self.new_error("expected identifier"))
1404
+
1405
+ if self.current_token.type == TOKENS['IDENTIFIER']:
1406
+ parameter = self.current_token
1407
+
1408
+ result.register_advancement()
1409
+ self.advance()
1410
+ self.skip_expression(result)
1411
+
1412
+ while (
1413
+ self.current_token.type in (
1414
+ TOKENS['AMPERSAND'],
1415
+ TOKENS['COMMA'],
1416
+ TOKENS['PIPE'],
1417
+ TOKENS['DOUBLE-AMPERSAND'],
1418
+ TOKENS['DOUBLE-PIPE']
1419
+ ) or
1420
+ self.current_token.match(TOKENS['KEYWORD'], 'and', 'or')
1421
+ ):
1422
+
1423
+ result.register_advancement()
1424
+ self.advance()
1425
+ self.skip_expression(result)
1426
+
1427
+ if self.current_token.type != TOKENS['IDENTIFIER']:
1428
+ return result.failure(self.new_error("expected identifier"))
1429
+
1430
+ targets.append(PysIdentifierNode(self.current_token))
1431
+
1432
+ result.register_advancement()
1433
+ self.advance()
1434
+ self.skip_expression(result)
1435
+
1436
+ if self.current_token.match(TOKENS['KEYWORD'], 'as'):
1437
+ result.register_advancement()
1438
+ self.advance()
1439
+ self.skip_expression(result)
1440
+
1441
+ if self.current_token.type != TOKENS['IDENTIFIER']:
1442
+ return result.failure(self.new_error("expected identifier"))
1443
+
1444
+ if self.current_token.type == TOKENS['IDENTIFIER']:
1445
+ targets.insert(0, PysIdentifierNode(parameter))
1446
+ parameter = self.current_token
1447
+
1448
+ result.register_advancement()
1449
+ self.advance()
1450
+ self.skip_expression(result)
1451
+
1452
+ else:
1453
+ all_catch_handler = True
1454
+
1455
+ else:
1456
+ all_catch_handler = True
1457
+
1458
+ if bracket:
1459
+ self.close_bracket(result, left_bracket_token)
1460
+ if result.error:
1461
+ return result
1462
+
1463
+ self.bracket_level -= 1
1464
+
1465
+ self.skip(result)
1466
+
1467
+ catch_body = result.register(self.block_statements(), True)
1468
+ if result.error:
1469
+ return result
1470
+
1471
+ catch_cases.append(((tuple(targets), parameter), catch_body))
1472
+ advance_count = self.skip(result)
1473
+
1474
+ if self.current_token.match(TOKENS['KEYWORD'], 'else'):
1475
+ result.register_advancement()
1476
+ self.advance()
1477
+ self.skip(result)
1478
+
1479
+ else_body = result.register(self.block_statements(), True)
1480
+ if result.error:
1481
+ return result
1482
+
1483
+ advance_count = self.skip(result)
1484
+
1485
+ if self.current_token.match(TOKENS['KEYWORD'], 'finally'):
1486
+ result.register_advancement()
1487
+ self.advance()
1488
+ self.skip(result)
1489
+
1490
+ finally_body = result.register(self.block_statements(), True)
1491
+ if result.error:
1492
+ return result
1493
+
1494
+ elif not catch_cases:
1495
+ return result.failure(self.new_error("expected 'catch', 'except', or 'finally'"))
1496
+
1497
+ else:
1498
+ self.reverse(advance_count)
1499
+
1500
+ return result.success(
1501
+ PysTryNode(
1502
+ body,
1503
+ catch_cases,
1504
+ else_body,
1505
+ finally_body,
1506
+ position
1507
+ )
1508
+ )
1509
+
1510
+ def with_statement(self):
1511
+ result = PysParserResult()
1512
+ position = self.current_token.position
1513
+
1514
+ if not self.current_token.match(TOKENS['KEYWORD'], 'with'):
1515
+ return result.failure(self.new_error("expected 'with'"))
1516
+
1517
+ result.register_advancement()
1518
+ self.advance()
1519
+ self.skip(result)
1520
+
1521
+ bracket = False
1522
+
1523
+ if self.current_token.type == TOKENS['LEFT-PARENTHESIS']:
1524
+ bracket = True
1525
+ left_bracket_token = self.current_token
1526
+ self.bracket_level += 1
1527
+
1528
+ result.register_advancement()
1529
+ self.advance()
1530
+ self.skip(result)
1531
+
1532
+ contexts = []
1533
+
1534
+ while True:
1535
+ context = result.register(self.single_expression(), True)
1536
+ if result.error:
1537
+ return result
1538
+
1539
+ if self.current_token.match(TOKENS['KEYWORD'], 'as'):
1540
+ result.register_advancement()
1541
+ self.advance()
1542
+ self.skip_expression(result)
1543
+
1544
+ if self.current_token.type != TOKENS['IDENTIFIER']:
1545
+ return result.failure(self.new_error("expected identifier"))
1546
+
1547
+ alias = None
1548
+
1549
+ if self.current_token.type == TOKENS['IDENTIFIER']:
1550
+ alias = self.current_token
1551
+
1552
+ result.register_advancement()
1553
+ self.advance()
1554
+ self.skip_expression(result)
1555
+
1556
+ contexts.append((context, alias))
1557
+
1558
+ if self.current_token.type == TOKENS['COMMA']:
1559
+ result.register_advancement()
1560
+ self.advance()
1561
+ self.skip_expression(result)
1562
+
1563
+ elif bracket and not is_right_bracket(self.current_token.type):
1564
+ return result.failure(self.new_error("invalid syntax. Perhaps you forgot a comma?"))
1565
+
1566
+ else:
1567
+ break
1568
+
1569
+ if bracket:
1570
+ self.close_bracket(result, left_bracket_token)
1571
+ if result.error:
1572
+ return result
1573
+
1574
+ self.bracket_level -= 1
1575
+
1576
+ self.skip(result)
1577
+
1578
+ body = result.register(self.block_statements(), True)
1579
+ if result.error:
1580
+ return result
1581
+
1582
+ return result.success(
1583
+ PysWithNode(
1584
+ contexts,
1585
+ body,
1586
+ position
1587
+ )
1588
+ )
1589
+
1590
+ def for_statement(self):
1591
+ result = PysParserResult()
1592
+ position = self.current_token.position
1593
+
1594
+ if not self.current_token.match(TOKENS['KEYWORD'], 'for'):
1595
+ return result.failure(self.new_error("expected 'for'"))
1596
+
1597
+ result.register_advancement()
1598
+ self.advance()
1599
+ self.skip(result)
1600
+
1601
+ bracket = False
1602
+
1603
+ if self.current_token.type == TOKENS['LEFT-PARENTHESIS']:
1604
+ bracket = True
1605
+ left_bracket_token = self.current_token
1606
+ self.bracket_level += 1
1607
+
1608
+ result.register_advancement()
1609
+ self.advance()
1610
+ self.skip(result)
1611
+
1612
+ declaration = result.try_register(self.assignment_statement(self.primary))
1613
+ if result.error:
1614
+ return result
1615
+
1616
+ if self.current_token.type == TOKENS['SEMICOLON']:
1617
+ foreach = False
1618
+
1619
+ result.register_advancement()
1620
+ self.advance()
1621
+ self.skip_expression(result)
1622
+
1623
+ condition = result.try_register(self.single_expression())
1624
+ if result.error:
1625
+ return result
1626
+
1627
+ if self.current_token.type != TOKENS['SEMICOLON']:
1628
+ return result.failure(self.new_error("expected ';'"))
1629
+
1630
+ result.register_advancement()
1631
+ self.advance()
1632
+ self.skip_expression(result)
1633
+
1634
+ update = result.try_register(self.assignment_statement())
1635
+ if result.error:
1636
+ return result
1637
+
1638
+ elif self.current_token.match(TOKENS['KEYWORD'], 'in', 'of'):
1639
+ if declaration is None:
1640
+ return result.failure(
1641
+ self.new_error(
1642
+ f"expected assign expression. Did you mean ';' instead of {self.current_token.value!r}?"
1643
+ )
1644
+ )
1645
+
1646
+ foreach = True
1647
+
1648
+ result.register_advancement()
1649
+ self.advance()
1650
+ self.skip_expression(result)
1651
+
1652
+ iteration = result.register(self.single_expression(), True)
1653
+ if result.error:
1654
+ return result
1655
+
1656
+ elif declaration is None:
1657
+ return result.failure(self.new_error("expected assign expression or ';'"))
1658
+
1659
+ else:
1660
+ return result.failure(self.new_error("expected 'in', 'of', or ';'"))
1661
+
1662
+ if bracket:
1663
+ self.close_bracket(result, left_bracket_token)
1664
+ if result.error:
1665
+ return result
1666
+
1667
+ self.bracket_level -= 1
1668
+
1669
+ self.skip(result)
1670
+
1671
+ body = result.register(self.block_statements(), True)
1672
+ if result.error:
1673
+ return result
1674
+
1675
+ else_body = None
1676
+ advance_count = self.skip(result)
1677
+
1678
+ if self.current_token.match(TOKENS['KEYWORD'], 'else'):
1679
+ result.register_advancement()
1680
+ self.advance()
1681
+ self.skip(result)
1682
+
1683
+ else_body = result.register(self.block_statements(), True)
1684
+ if result.error:
1685
+ return result
1686
+
1687
+ else:
1688
+ self.reverse(advance_count)
1689
+
1690
+ return result.success(
1691
+ PysForNode(
1692
+ (declaration, iteration) if foreach else (declaration, condition, update),
1693
+ body,
1694
+ else_body,
1695
+ position
1696
+ )
1697
+ )
1698
+
1699
+ def while_statement(self):
1700
+ result = PysParserResult()
1701
+ position = self.current_token.position
1702
+
1703
+ if not self.current_token.match(TOKENS['KEYWORD'], 'while'):
1704
+ return result.failure(self.new_error("expected 'while'"))
1705
+
1706
+ result.register_advancement()
1707
+ self.advance()
1708
+ self.skip(result)
1709
+
1710
+ condition = result.register(self.walrus(), True)
1711
+ if result.error:
1712
+ return result
1713
+
1714
+ self.skip(result)
1715
+
1716
+ body = result.register(self.block_statements(), True)
1717
+ if result.error:
1718
+ return result
1719
+
1720
+ else_body = None
1721
+ advance_count = self.skip(result)
1722
+
1723
+ if self.current_token.match(TOKENS['KEYWORD'], 'else'):
1724
+ result.register_advancement()
1725
+ self.advance()
1726
+ self.skip(result)
1727
+
1728
+ else_body = result.register(self.block_statements(), True)
1729
+ if result.error:
1730
+ return result
1731
+
1732
+ else:
1733
+ self.reverse(advance_count)
1734
+
1735
+ return result.success(
1736
+ PysWhileNode(
1737
+ condition,
1738
+ body,
1739
+ else_body,
1740
+ position
1741
+ )
1742
+ )
1743
+
1744
+ def do_while_statement(self):
1745
+ result = PysParserResult()
1746
+ position = self.current_token.position
1747
+
1748
+ if not self.current_token.match(TOKENS['KEYWORD'], 'do'):
1749
+ return result.failure(self.new_error("expected 'do'"))
1750
+
1751
+ result.register_advancement()
1752
+ self.advance()
1753
+ self.skip(result)
1754
+
1755
+ body = result.register(self.block_statements(), True)
1756
+ if result.error:
1757
+ return result
1758
+
1759
+ self.skip(result)
1760
+
1761
+ if not self.current_token.match(TOKENS['KEYWORD'], 'while'):
1762
+ return result.failure(self.new_error("expected 'while'"))
1763
+
1764
+ result.register_advancement()
1765
+ self.advance()
1766
+ self.skip(result)
1767
+
1768
+ condition = result.register(self.walrus(), True)
1769
+ if result.error:
1770
+ return result
1771
+
1772
+ else_body = None
1773
+ advance_count = self.skip(result)
1774
+
1775
+ if self.current_token.match(TOKENS['KEYWORD'], 'else'):
1776
+ result.register_advancement()
1777
+ self.advance()
1778
+ self.skip(result)
1779
+
1780
+ else_body = result.register(self.block_statements(), True)
1781
+ if result.error:
1782
+ return result
1783
+
1784
+ else:
1785
+ self.reverse(advance_count)
1786
+
1787
+ return result.success(
1788
+ PysDoWhileNode(
1789
+ body,
1790
+ condition,
1791
+ else_body,
1792
+ position
1793
+ )
1794
+ )
1795
+
1796
+ def repeat_statement(self):
1797
+ result = PysParserResult()
1798
+ position = self.current_token.position
1799
+
1800
+ if not self.current_token.match(TOKENS['KEYWORD'], 'repeat'):
1801
+ return result.failure(self.new_error("expected 'repeat'"))
1802
+
1803
+ result.register_advancement()
1804
+ self.advance()
1805
+ self.skip(result)
1806
+
1807
+ body = result.register(self.block_statements(), True)
1808
+ if result.error:
1809
+ return result
1810
+
1811
+ self.skip(result)
1812
+
1813
+ if not self.current_token.match(TOKENS['KEYWORD'], 'until'):
1814
+ return result.failure(self.new_error("expected 'until'"))
1815
+
1816
+ result.register_advancement()
1817
+ self.advance()
1818
+ self.skip(result)
1819
+
1820
+ condition = result.register(self.walrus(), True)
1821
+ if result.error:
1822
+ return result
1823
+
1824
+ else_body = None
1825
+ advance_count = self.skip(result)
1826
+
1827
+ if self.current_token.match(TOKENS['KEYWORD'], 'else'):
1828
+ result.register_advancement()
1829
+ self.advance()
1830
+ self.skip(result)
1831
+
1832
+ else_body = result.register(self.block_statements(), True)
1833
+ if result.error:
1834
+ return result
1835
+
1836
+ else:
1837
+ self.reverse(advance_count)
1838
+
1839
+ return result.success(
1840
+ PysRepeatNode(
1841
+ body,
1842
+ condition,
1843
+ else_body,
1844
+ position
1845
+ )
1846
+ )
1847
+
1848
+ def class_statement(self, decorators=None):
1849
+ result = PysParserResult()
1850
+ start = self.current_token.position.start
1851
+
1852
+ if not self.current_token.match(TOKENS['KEYWORD'], 'class'):
1853
+ return result.failure(self.new_error("expected 'class'"))
1854
+
1855
+ result.register_advancement()
1856
+ self.advance()
1857
+ self.skip(result)
1858
+
1859
+ if self.current_token.type != TOKENS['IDENTIFIER']:
1860
+ return result.failure(self.new_error("expected identifier"))
1861
+
1862
+ end = self.current_token.position.end
1863
+ name = self.current_token
1864
+ has_bases = False
1865
+
1866
+ result.register_advancement()
1867
+ self.advance()
1868
+ self.skip(result)
1869
+
1870
+ if self.current_token.type == TOKENS['LEFT-PARENTHESIS']:
1871
+ has_bases = True
1872
+
1873
+ base = result.register(self.sequence_expression('tuple', should_sequence=True))
1874
+ if result.error:
1875
+ return result
1876
+
1877
+ end = base.position.end
1878
+ bases = list(base.elements)
1879
+
1880
+ elif self.current_token.match(TOKENS['KEYWORD'], 'extends'):
1881
+ has_bases = True
1882
+
1883
+ result.register_advancement()
1884
+ self.advance()
1885
+ self.skip(result)
1886
+
1887
+ base = result.register(self.expression(), True)
1888
+ if result.error:
1889
+ return result
1890
+
1891
+ end = base.position.end
1892
+ bases = list(base.elements) if is_list(base.__class__) else [base]
1893
+
1894
+ else:
1895
+ bases = []
1896
+
1897
+ if self.current_token.type == TOKENS['COLON']:
1898
+ return result.failure(self.new_error("unlike python"))
1899
+
1900
+ body = result.register(self.block_statements(), True)
1901
+ if result.error:
1902
+ return result.failure(
1903
+ self.new_error(
1904
+ "expected statement, expression, '{', or ';'"
1905
+ if has_bases else
1906
+ "expected statement, expression, 'extends', '(', '{', or ';'"
1907
+ )
1908
+ )
1909
+
1910
+ return result.success(
1911
+ PysClassNode(
1912
+ [] if decorators is None else decorators,
1913
+ name,
1914
+ bases,
1915
+ body,
1916
+ PysPosition(
1917
+ self.current_token.position.file,
1918
+ start,
1919
+ end
1920
+ )
1921
+ )
1922
+ )
1923
+
1924
+ def func_expression(self, decorators=None):
1925
+ result = PysParserResult()
1926
+ position = self.current_token.position
1927
+ start = position.start
1928
+ constructor = False
1929
+
1930
+ if self.current_token.match(TOKENS['KEYWORD'], 'constructor'):
1931
+ constructor = True
1932
+ elif not self.current_token.match(TOKENS['KEYWORD'], 'def', 'define', 'func', 'function'):
1933
+ return result.failure(self.new_error("expected 'def', 'define', 'func', 'function', or 'constructor'"))
1934
+
1935
+ result.register_advancement()
1936
+ self.advance()
1937
+ self.skip(result)
1938
+
1939
+ name = None
1940
+ parameters = []
1941
+
1942
+ if constructor:
1943
+ name = PysToken(TOKENS['IDENTIFIER'], position, '__init__')
1944
+ parameters.append(PysToken(TOKENS['IDENTIFIER'], position, 'self'))
1945
+
1946
+ elif self.current_token.type == TOKENS['IDENTIFIER']:
1947
+ name = self.current_token
1948
+ result.register_advancement()
1949
+ self.advance()
1950
+ self.skip(result)
1951
+
1952
+ if self.current_token.type != TOKENS['LEFT-PARENTHESIS']:
1953
+ return result.failure(self.new_error("expected identifier or '('" if name is None else "expected '('"))
1954
+
1955
+ left_bracket_token = self.current_token
1956
+ self.bracket_level += 1
1957
+
1958
+ result.register_advancement()
1959
+ self.advance()
1960
+ self.skip(result)
1961
+
1962
+ seen_keyword_argument = False
1963
+
1964
+ while not is_right_bracket(self.current_token.type):
1965
+ if self.current_token.type != TOKENS['IDENTIFIER']:
1966
+ return result.failure(self.new_error("expected identifier"))
1967
+
1968
+ key = self.current_token
1969
+
1970
+ result.register_advancement()
1971
+ self.advance()
1972
+ self.skip(result)
1973
+
1974
+ if self.current_token.type == TOKENS['EQUAL']:
1975
+ result.register_advancement()
1976
+ self.advance()
1977
+ self.skip(result)
1978
+ seen_keyword_argument = True
1979
+
1980
+ elif seen_keyword_argument:
1981
+ return result.failure(self.new_error("expected '=' (follows keyword argument)"))
1982
+
1983
+ if seen_keyword_argument:
1984
+ value = result.register(self.single_expression(), True)
1985
+ if result.error:
1986
+ return result
1987
+ parameters.append((key, value))
1988
+ else:
1989
+ parameters.append(key)
1990
+
1991
+ self.skip(result)
1992
+
1993
+ if self.current_token.type == TOKENS['COMMA']:
1994
+ result.register_advancement()
1995
+ self.advance()
1996
+ self.skip(result)
1997
+
1998
+ elif not is_right_bracket(self.current_token.type):
1999
+ return result.failure(self.new_error("invalid syntax. Perhaps you forgot a comma?"))
2000
+
2001
+ end = self.current_token.position.end
2002
+
2003
+ self.close_bracket(result, left_bracket_token)
2004
+ if result.error:
2005
+ return result
2006
+
2007
+ self.bracket_level -= 1
2008
+ self.skip(result)
2009
+
2010
+ if not constructor and self.current_token.type == TOKENS['EQUAL-ARROW']:
2011
+ position = self.current_token.position
2012
+ result.register_advancement()
2013
+ self.advance()
2014
+ self.skip(result)
2015
+
2016
+ body = result.register(self.single_expression(), True)
2017
+ if result.error:
2018
+ return result
2019
+
2020
+ body = PysReturnNode(body, position)
2021
+
2022
+ elif self.current_token.type == TOKENS['COLON']:
2023
+ return result.failure(self.new_error("unlike python"))
2024
+
2025
+ else:
2026
+ body = result.register(self.block_statements(), True)
2027
+ if result.error:
2028
+ return result.failure(
2029
+ self.new_error(
2030
+ "expected statement, expression, '{', or ';'"
2031
+ if constructor else
2032
+ "expected statement, expression, '{', ';', or '=>'"
2033
+ )
2034
+ )
2035
+
2036
+ self.skip_expression(result)
2037
+
2038
+ return result.success(
2039
+ PysFunctionNode(
2040
+ [] if decorators is None else decorators,
2041
+ name,
2042
+ parameters,
2043
+ body,
2044
+ constructor,
2045
+ PysPosition(self.current_token.position.file, start, end)
2046
+ )
2047
+ )
2048
+
2049
+ def return_statement(self):
2050
+ result = PysParserResult()
2051
+ position = self.current_token.position
2052
+
2053
+ if not self.current_token.match(TOKENS['KEYWORD'], 'return'):
2054
+ return result.failure(self.new_error("expected 'return'"))
2055
+
2056
+ result.register_advancement()
2057
+ self.advance()
2058
+ self.skip(result)
2059
+
2060
+ value = result.try_register(self.expression())
2061
+ if result.error:
2062
+ return result
2063
+
2064
+ if not value:
2065
+ self.reverse(result.to_reverse_count)
2066
+
2067
+ return result.success(
2068
+ PysReturnNode(
2069
+ value,
2070
+ position
2071
+ )
2072
+ )
2073
+
2074
+ def global_statement(self):
2075
+ result = PysParserResult()
2076
+ position = self.current_token.position
2077
+
2078
+ if not self.current_token.match(TOKENS['KEYWORD'], 'global'):
2079
+ return result.failure(self.new_error("expected 'global'"))
2080
+
2081
+ result.register_advancement()
2082
+ self.advance()
2083
+ self.skip(result)
2084
+
2085
+ names = []
2086
+ bracket = False
2087
+
2088
+ if self.current_token.type == TOKENS['LEFT-PARENTHESIS']:
2089
+ bracket = True
2090
+ left_bracket_token = self.current_token
2091
+ self.bracket_level += 1
2092
+
2093
+ result.register_advancement()
2094
+ self.advance()
2095
+ self.skip(result)
2096
+
2097
+ elif is_left_bracket(self.current_token.type):
2098
+ return result.failure(self.new_error(f"expected '(' not {chr(self.current_token.type)!r}"))
2099
+
2100
+ if self.current_token.type != TOKENS['IDENTIFIER']:
2101
+ return result.failure(self.new_error("expected identifier"))
2102
+
2103
+ while self.current_token.type == TOKENS['IDENTIFIER']:
2104
+ names.append(self.current_token)
2105
+
2106
+ result.register_advancement()
2107
+ self.advance()
2108
+ self.skip_expression(result)
2109
+
2110
+ if self.current_token.type == TOKENS['COMMA']:
2111
+ result.register_advancement()
2112
+ self.advance()
2113
+ self.skip_expression(result)
2114
+
2115
+ elif bracket and not is_right_bracket(self.current_token.type):
2116
+ return result.failure(self.new_error("invalid syntax. Perhaps you forgot a comma?"))
2117
+
2118
+ else:
2119
+ break
2120
+
2121
+ if bracket:
2122
+ self.close_bracket(result, left_bracket_token)
2123
+ if result.error:
2124
+ return result
2125
+
2126
+ self.bracket_level -= 1
2127
+
2128
+ return result.success(
2129
+ PysGlobalNode(
2130
+ names,
2131
+ position
2132
+ )
2133
+ )
2134
+
2135
+ def del_statement(self):
2136
+ result = PysParserResult()
2137
+ position = self.current_token.position
2138
+
2139
+ if not self.current_token.match(TOKENS['KEYWORD'], 'del', 'delete'):
2140
+ return result.failure(self.new_error("expected 'del' or 'delete'"))
2141
+
2142
+ result.register_advancement()
2143
+ self.advance()
2144
+ self.skip(result)
2145
+
2146
+ targets = result.register(self.expression(), True)
2147
+ if result.error:
2148
+ return result
2149
+
2150
+ return result.success(
2151
+ PysDeleteNode(
2152
+ list(targets.elements) if is_list(targets.__class__) else [targets],
2153
+ position
2154
+ )
2155
+ )
2156
+
2157
+ def throw_statement(self):
2158
+ result = PysParserResult()
2159
+ position = self.current_token.position
2160
+
2161
+ if not self.current_token.match(TOKENS['KEYWORD'], 'raise', 'throw'):
2162
+ return result.failure(self.new_error("expected 'raise' or 'throw'"))
2163
+
2164
+ result.register_advancement()
2165
+ self.advance()
2166
+ self.skip(result)
2167
+
2168
+ target = result.register(self.single_expression(), True)
2169
+ if result.error:
2170
+ return result
2171
+
2172
+ cause = None
2173
+
2174
+ if self.current_token.match(TOKENS['KEYWORD'], 'from'):
2175
+ result.register_advancement()
2176
+ self.advance()
2177
+ self.skip(result)
2178
+
2179
+ cause = result.register(self.single_expression(), True)
2180
+ if result.error:
2181
+ return result
2182
+
2183
+ return result.success(
2184
+ PysThrowNode(
2185
+ target,
2186
+ cause,
2187
+ position
2188
+ )
2189
+ )
2190
+
2191
+ def assert_statement(self):
2192
+ result = PysParserResult()
2193
+
2194
+ if not self.current_token.match(TOKENS['KEYWORD'], 'assert'):
2195
+ return result.failure(self.new_error("expected 'assert'"))
2196
+
2197
+ result.register_advancement()
2198
+ self.advance()
2199
+ self.skip(result)
2200
+
2201
+ condition = result.register(self.single_expression(), True)
2202
+ if result.error:
2203
+ return result
2204
+
2205
+ message = None
2206
+ advance_count = self.skip(result)
2207
+
2208
+ if self.current_token.type == TOKENS['COMMA']:
2209
+ result.register_advancement()
2210
+ self.advance()
2211
+ self.skip(result)
2212
+
2213
+ message = result.register(self.single_expression(), True)
2214
+ if result.error:
2215
+ return result
2216
+
2217
+ else:
2218
+ self.reverse(advance_count)
2219
+
2220
+ return result.success(
2221
+ PysAssertNode(
2222
+ condition,
2223
+ message
2224
+ )
2225
+ )
2226
+
2227
+ def decorator(self):
2228
+ result = PysParserResult()
2229
+
2230
+ if self.current_token.type != TOKENS['AT']:
2231
+ return result.failure(self.new_error("expected '@'"))
2232
+
2233
+ decorators = []
2234
+
2235
+ while self.current_token.type == TOKENS['AT']:
2236
+ result.register_advancement()
2237
+ self.advance()
2238
+
2239
+ decorators.append(result.register(self.walrus(), True))
2240
+ if result.error:
2241
+ return result
2242
+
2243
+ self.skip(result, TOKENS['NEWLINE'], TOKENS['SEMICOLON'])
2244
+
2245
+ if self.current_token.match(TOKENS['KEYWORD'], 'def', 'define', 'func', 'function'):
2246
+ func_expression = result.register(self.func_expression(decorators))
2247
+ if result.error:
2248
+ return result
2249
+
2250
+ return result.success(func_expression)
2251
+
2252
+ elif self.current_token.match(TOKENS['KEYWORD'], 'class'):
2253
+ class_expression = result.register(self.class_statement(decorators))
2254
+ if result.error:
2255
+ return result
2256
+
2257
+ return result.success(class_expression)
2258
+
2259
+ return result.failure(self.new_error("expected function or class declaration after decorator"))
2260
+
2261
+ def block_statements(self):
2262
+ result = PysParserResult()
2263
+
2264
+ if self.current_token.type == TOKENS['LEFT-CURLY']:
2265
+ left_bracket_token = self.current_token
2266
+
2267
+ result.register_advancement()
2268
+ self.advance()
2269
+
2270
+ body = result.register(self.statements())
2271
+ if result.error:
2272
+ return result
2273
+
2274
+ end = self.current_token.position.end
2275
+
2276
+ self.close_bracket(result, left_bracket_token)
2277
+ if result.error:
2278
+ return result
2279
+
2280
+ if isinstance(body, PysStatementsNode):
2281
+ setimuattr(
2282
+ body, 'position',
2283
+ PysPosition(
2284
+ self.current_token.position.file,
2285
+ left_bracket_token.position.start,
2286
+ end
2287
+ )
2288
+ )
2289
+
2290
+ return result.success(body)
2291
+
2292
+ elif self.current_token.type == TOKENS['SEMICOLON']:
2293
+ position = self.current_token.position
2294
+
2295
+ result.register_advancement()
2296
+ self.advance()
2297
+
2298
+ return result.success(
2299
+ PysStatementsNode(
2300
+ [],
2301
+ position
2302
+ )
2303
+ )
2304
+
2305
+ elif self.current_token.type == TOKENS['COLON']:
2306
+ return result.failure(self.new_error("unlike python"))
2307
+
2308
+ body = result.register(self.statement())
2309
+ if result.error:
2310
+ return result.failure(
2311
+ self.new_error("expected statement, expression, '{', or ';'"),
2312
+ fatal=False
2313
+ )
2314
+
2315
+ return result.success(body)
2316
+
2317
+ def chain_operator(self, func, *operators, membership=False):
2318
+ result = PysParserResult()
2319
+
2320
+ operations = []
2321
+ expressions = []
2322
+
2323
+ expression = result.register(func())
2324
+ if result.error:
2325
+ return result
2326
+
2327
+ while self.current_token.type in operators or (self.current_token.type, self.current_token.value) in operators:
2328
+ operations.append(self.current_token)
2329
+ expressions.append(expression)
2330
+
2331
+ if membership and self.current_token.match(TOKENS['KEYWORD'], 'not'):
2332
+ result.register_advancement()
2333
+ self.advance()
2334
+ self.skip_expression(result)
2335
+
2336
+ if not self.current_token.match(TOKENS['KEYWORD'], 'in'):
2337
+ return result.failure(self.new_error("expected 'in'"))
2338
+
2339
+ operations[-1] = PysToken(
2340
+ TOKENS['NOT-IN'],
2341
+ self.current_token.position,
2342
+ 'not in'
2343
+ )
2344
+
2345
+ last_token = self.current_token
2346
+
2347
+ result.register_advancement()
2348
+ self.advance()
2349
+ self.skip_expression(result)
2350
+
2351
+ if (
2352
+ membership and
2353
+ last_token.match(TOKENS['KEYWORD'], 'is') and
2354
+ self.current_token.match(TOKENS['KEYWORD'], 'not')
2355
+ ):
2356
+ operations[-1] = PysToken(
2357
+ TOKENS['IS-NOT'],
2358
+ self.current_token.position,
2359
+ 'is not'
2360
+ )
2361
+
2362
+ result.register_advancement()
2363
+ self.advance()
2364
+ self.skip_expression(result)
2365
+
2366
+ expression = result.register(func(), True)
2367
+ if result.error:
2368
+ return result
2369
+
2370
+ if operations:
2371
+ expressions.append(expression)
2372
+
2373
+ return result.success(
2374
+ PysChainOperatorNode(
2375
+ operations,
2376
+ expressions
2377
+ ) if operations else expression
2378
+ )
2379
+
2380
+ def binary_operator(self, func, *operators):
2381
+ result = PysParserResult()
2382
+
2383
+ left = result.register(func())
2384
+ if result.error:
2385
+ return result
2386
+
2387
+ while self.current_token.type in operators or (self.current_token.type, self.current_token.value) in operators:
2388
+ operand = self.current_token
2389
+
2390
+ result.register_advancement()
2391
+ self.advance()
2392
+ self.skip_expression(result)
2393
+
2394
+ right = result.register(func(), True)
2395
+ if result.error:
2396
+ return result
2397
+
2398
+ left = PysBinaryOperatorNode(left, operand, right)
2399
+
2400
+ return result.success(left)
2401
+
2402
+ def close_bracket(self, result, left_bracket_token):
2403
+ if self.current_token.type != BRACKETS_MAP[left_bracket_token.type]:
2404
+
2405
+ if is_right_bracket(self.current_token.type):
2406
+ result.failure(
2407
+ self.new_error(
2408
+ f"closing parenthesis {chr(self.current_token.type)!r} "
2409
+ f"does not match opening parenthesis {chr(left_bracket_token.type)!r}"
2410
+ )
2411
+ )
2412
+
2413
+ elif self.current_token.type == TOKENS['NULL']:
2414
+ result.failure(
2415
+ self.new_error(
2416
+ f"{chr(left_bracket_token.type)!r} was never closed",
2417
+ left_bracket_token.position
2418
+ )
2419
+ )
2420
+
2421
+ else:
2422
+ result.failure(self.new_error("invalid syntax"))
2423
+
2424
+ return
2425
+
2426
+ result.register_advancement()
2427
+ self.advance()
2428
+
2429
+ def skip(self, result, *types):
2430
+ types = types or (TOKENS['NEWLINE'],)
2431
+ count = 0
2432
+
2433
+ while self.current_token.type in types:
2434
+ result.register_advancement()
2435
+ self.advance()
2436
+ count += 1
2437
+
2438
+ return count
2439
+
2440
+ def skip_expression(self, result):
2441
+ return self.skip(result) if self.bracket_level > 0 else 0
2442
+
2443
+ def proccess_future(self, name):
2444
+ result = PysParserResult()
2445
+
2446
+ if name == 'braces':
2447
+ return result.failure(self.new_error("yes, i use it for this language"))
2448
+
2449
+ elif name == 'indent':
2450
+ return result.failure(self.new_error("not a chance"))
2451
+
2452
+ elif name in ('dict_to_jsdict', 'dict2jsdict'):
2453
+ self.parser_flags |= DICT_TO_JSDICT
2454
+ return result.success(True)
2455
+
2456
+ return result.failure(self.new_error(f"future feature {name} is not defined"))