pyscript-programming-language 1.7.2__tar.gz → 1.8.0__tar.gz

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 (77) hide show
  1. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/PKG-INFO +2 -2
  2. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/__main__.py +16 -15
  3. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/analyzer.py +29 -7
  4. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/checks.py +1 -1
  5. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/constants.py +1 -0
  6. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/exceptions.py +3 -1
  7. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/highlight.py +19 -4
  8. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/interpreter.py +50 -1
  9. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/lexer.py +8 -9
  10. pyscript_programming_language-1.8.0/pyscript/core/mapping.py +131 -0
  11. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/nodes.py +26 -1
  12. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/objects.py +5 -4
  13. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/parser.py +102 -9
  14. pyscript_programming_language-1.8.0/pyscript/core/position.py +99 -0
  15. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/pysbuiltins.py +178 -19
  16. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/runner.py +3 -0
  17. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/decorators.py +5 -4
  18. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/generic.py +29 -14
  19. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/module.py +1 -1
  20. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/shell.py +4 -0
  21. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/version.py +2 -2
  22. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/ast/__init__.pys +6 -0
  23. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/ast/ast_dump.py +12 -6
  24. pyscript_programming_language-1.8.0/pyscript/lib/ast/ast_literal_eval.py +51 -0
  25. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/ast/ast_unparse.py +37 -69
  26. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/ast/ast_walk.py +13 -0
  27. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/brainfuck.pys +3 -3
  28. pyscript_programming_language-1.8.0/pyscript/lib/dis.pys +7 -0
  29. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/sys.pys +1 -0
  30. pyscript_programming_language-1.8.0/pyscript/lib/token.pys +12 -0
  31. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/tokenize/__init__.pys +3 -1
  32. pyscript_programming_language-1.8.0/pyscript/lib/tokenize/tok_untokenize.py +27 -0
  33. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript_programming_language.egg-info/PKG-INFO +2 -2
  34. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript_programming_language.egg-info/SOURCES.txt +1 -0
  35. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/setup.py +2 -2
  36. pyscript_programming_language-1.7.2/pyscript/core/mapping.py +0 -67
  37. pyscript_programming_language-1.7.2/pyscript/core/position.py +0 -99
  38. pyscript_programming_language-1.7.2/pyscript/lib/dis.pys +0 -7
  39. pyscript_programming_language-1.7.2/pyscript/lib/token.pys +0 -1
  40. pyscript_programming_language-1.7.2/pyscript/lib/tokenize/tok_untokenize.py +0 -89
  41. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/MANIFEST.in +0 -0
  42. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/README.md +0 -0
  43. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/__init__.py +0 -0
  44. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/__init__.pyi +0 -0
  45. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/__init__.py +0 -0
  46. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/bases.py +0 -0
  47. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/buffer.py +0 -0
  48. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/cache.py +0 -0
  49. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/context.py +0 -0
  50. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/handlers.py +0 -0
  51. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/results.py +0 -0
  52. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/symtab.py +0 -0
  53. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/token.py +0 -0
  54. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/__init__.py +0 -0
  55. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/ansi.py +0 -0
  56. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/debug.py +0 -0
  57. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/path.py +0 -0
  58. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/similarity.py +0 -0
  59. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/core/utils/string.py +0 -0
  60. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/__hello__.pys +0 -0
  61. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/ansi.pys +0 -0
  62. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/explorer.pys +0 -0
  63. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/fpstimer.pys +0 -0
  64. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/getch.pys +0 -0
  65. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/inspect.pys +0 -0
  66. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/jsdict.pys +0 -0
  67. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/keyword.pys +0 -0
  68. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/parser.pys +0 -0
  69. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/site.pys +0 -0
  70. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/symtable.pys +0 -0
  71. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/lib/this.pys +0 -0
  72. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/site-packages/67.pys +0 -0
  73. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript/this.py +0 -0
  74. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript_programming_language.egg-info/dependency_links.txt +0 -0
  75. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript_programming_language.egg-info/requires.txt +0 -0
  76. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/pyscript_programming_language.egg-info/top_level.txt +0 -0
  77. {pyscript_programming_language-1.7.2 → pyscript_programming_language-1.8.0}/setup.cfg +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyscript-programming-language
3
- Version: 1.7.2
3
+ Version: 1.8.0
4
4
  Summary: PyScript Programming Language
5
- Home-page: https://github.com/azzammuhyala/pyscript
5
+ Home-page: https://azzammuhyala.github.io/pyscript
6
6
  Author: azzammuhyala
7
7
  Author-email: azzammuhyala@gmail.com
8
8
  License: MIT
@@ -9,7 +9,8 @@ from .core.version import __version__
9
9
 
10
10
  from argparse import ArgumentParser
11
11
  from os import environ
12
- from sys import executable, stderr, version_info, exit, setrecursionlimit
12
+
13
+ import sys
13
14
 
14
15
  FORMAT_HIGHLIGHT_MAP = {
15
16
  'html': HLFMT_HTML,
@@ -18,8 +19,8 @@ FORMAT_HIGHLIGHT_MAP = {
18
19
  }
19
20
 
20
21
  parser = ArgumentParser(
21
- prog=f'{get_module_name_from_path(executable)} -m pyscript',
22
- description=f'PyScript Launcher for Python Version {".".join(map(str, version_info))}'
22
+ prog=f'{get_module_name_from_path(sys.executable)} -m pyscript',
23
+ description=f'PyScript Launcher for Python Version {".".join(map(str, sys.version_info))}'
23
24
  )
24
25
 
25
26
  parser.add_argument(
@@ -27,7 +28,7 @@ parser.add_argument(
27
28
  type=str,
28
29
  nargs='?',
29
30
  default=None,
30
- help="file path"
31
+ help="File path to be executed"
31
32
  )
32
33
 
33
34
  parser.add_argument(
@@ -40,53 +41,53 @@ parser.add_argument(
40
41
  '-c', '--command',
41
42
  type=str,
42
43
  default=None,
43
- help="execute PyScript from argument",
44
+ help="Execute program from a string argument",
44
45
  )
45
46
 
46
47
  parser.add_argument(
47
48
  '-d', '--debug',
48
49
  action='store_true',
49
- help="set a debug flag, this will remove the assert statement"
50
+ help="Set a debug flag, this will remove the assert statement"
50
51
  )
51
52
 
52
53
  parser.add_argument(
53
54
  '-i', '--inspect',
54
55
  action='store_true',
55
- help="inspect interactively after running a file",
56
+ help="Inspect interactively after running a 'file'",
56
57
  )
57
58
 
58
59
  parser.add_argument(
59
60
  '-l', '--highlight',
60
61
  choices=tuple(FORMAT_HIGHLIGHT_MAP.keys()),
61
62
  default=None,
62
- help='generate PyScript highlight code from a file'
63
+ help="Generate highlight code from a 'file'"
63
64
  )
64
65
 
65
66
  parser.add_argument(
66
67
  '-n', '--no-color',
67
68
  action='store_true',
68
- help="no colorful traceback"
69
+ help="Suppress colored output"
69
70
  )
70
71
 
71
72
  parser.add_argument(
72
73
  '-r', '--py-recursion',
73
74
  type=int,
74
75
  default=None,
75
- help="set a python recursion limit"
76
+ help="Set a Python recursion limit"
76
77
  )
77
78
 
78
79
  def argument_error(argument, message):
79
- parser.print_usage(stderr)
80
+ parser.print_usage(sys.stderr)
80
81
  parser.exit(2, f"{parser.prog}: error: argument {argument}: {message}\n")
81
82
 
82
83
  args = parser.parse_args()
83
84
 
84
85
  if args.highlight and args.file is None:
85
- argument_error("-l/--highlight", "file path require")
86
+ argument_error("-l/--highlight", "argument 'file' required")
86
87
 
87
88
  if args.py_recursion is not None:
88
89
  try:
89
- setrecursionlimit(args.py_recursion)
90
+ sys.setrecursionlimit(args.py_recursion)
90
91
  except BaseException as e:
91
92
  argument_error("-r/--py-recursion", e)
92
93
 
@@ -121,7 +122,7 @@ if args.file is not None:
121
122
 
122
123
  if args.highlight:
123
124
  try:
124
- print(pys_highlight(file, FORMAT_HIGHLIGHT_MAP.get(args.highlight, None)))
125
+ print(pys_highlight(file, FORMAT_HIGHLIGHT_MAP.get(args.highlight)))
125
126
  except BaseException as e:
126
127
  parser.error(f"file {path!r}: Highlight error: {e}")
127
128
 
@@ -150,4 +151,4 @@ elif args.command is not None:
150
151
  else:
151
152
  code = pys_shell(undefined, flags)
152
153
 
153
- exit(code)
154
+ sys.exit(code)
@@ -157,23 +157,25 @@ class PysAnalyzer(Pys):
157
157
  self.visit(node.right)
158
158
 
159
159
  def visit_UnaryOperatorNode(self, node):
160
+ value = node.value
161
+
160
162
  if is_incremental(node.operand.type):
161
- type = node.value.__class__
163
+ type = value.__class__
162
164
  operator = 'increase' if node.operand.type == TOKENS['DOUBLE-PLUS'] else 'decrease'
163
165
 
164
166
  if type is PysKeywordNode:
165
- self.throw(f"cannot {operator} {node.value.token.value}", node.value.position)
167
+ self.throw(f"cannot {operator} {value.name.value}", value.position)
166
168
  return
167
169
 
168
- elif isinstance(node.value, PysNode):
170
+ elif isinstance(value, PysNode):
169
171
  if type not in (PysIdentifierNode, PysAttributeNode, PysSubscriptNode):
170
- self.throw(f"cannot {operator} literal", node.value.position)
172
+ self.throw(f"cannot {operator} literal", value.position)
171
173
  return
172
174
 
173
175
  else:
174
176
  raise TypeError("UnaryOperator: node.value is not PysNode")
175
177
 
176
- self.visit(node.value)
178
+ self.visit(value)
177
179
 
178
180
  def visit_StatementsNode(self, node):
179
181
  for element in node.body:
@@ -228,6 +230,26 @@ class PysAnalyzer(Pys):
228
230
 
229
231
  self.in_switch -= 1
230
232
 
233
+ def visit_MatchNode(self, node):
234
+ if node.target:
235
+ self.visit(node.target)
236
+ if self.error:
237
+ return
238
+
239
+ for condition, value in node.cases:
240
+ self.visit(condition)
241
+ if self.error:
242
+ return
243
+
244
+ self.visit(value)
245
+ if self.error:
246
+ return
247
+
248
+ if node.default:
249
+ self.visit(node.default)
250
+ if self.error:
251
+ return
252
+
231
253
  def visit_TryNode(self, node):
232
254
  self.visit(node.body)
233
255
  if self.error:
@@ -435,7 +457,7 @@ class PysAnalyzer(Pys):
435
457
  return
436
458
 
437
459
  elif type is PysKeywordNode:
438
- self.throw(f"cannot delete {target.token.value}", target.position)
460
+ self.throw(f"cannot delete {target.name.value}", target.position)
439
461
  return
440
462
 
441
463
  elif isinstance(target, PysNode):
@@ -502,7 +524,7 @@ class PysAnalyzer(Pys):
502
524
  return
503
525
 
504
526
  elif type is PysKeywordNode:
505
- self.throw(f"cannot assign to {node.token.value}", node.position)
527
+ self.throw(f"cannot assign to {node.name.value}", node.position)
506
528
 
507
529
  elif isinstance(node, PysNode):
508
530
  if type is not PysIdentifierNode:
@@ -5,7 +5,7 @@ from .nodes import *
5
5
  is_expression = frozenset([
6
6
  PysNumberNode, PysStringNode, PysKeywordNode, PysIdentifierNode, PysDictionaryNode, PysSetNode, PysListNode,
7
7
  PysTupleNode, PysAttributeNode, PysSubscriptNode, PysCallNode, PysChainOperatorNode, PysTernaryOperatorNode,
8
- PysBinaryOperatorNode, PysUnaryOperatorNode, PysFunctionNode, PysEllipsisNode
8
+ PysBinaryOperatorNode, PysUnaryOperatorNode, PysMatchNode, PysFunctionNode, PysEllipsisNode
9
9
  ]).__contains__
10
10
 
11
11
  is_statement = frozenset([
@@ -121,6 +121,7 @@ KEYWORDS = MappingProxyType({
121
121
  'import': 'import',
122
122
  'in': 'in',
123
123
  'is': 'is',
124
+ 'match': 'match',
124
125
  'none': 'none',
125
126
  'not': 'not',
126
127
  'true': 'true',
@@ -21,6 +21,8 @@ class PysTraceback(Pys):
21
21
  return f'<traceback of exception {self.exception!r}>'
22
22
 
23
23
  def string_traceback(self):
24
+ from .position import format_arrow # circular import problem solved
25
+
24
26
  context = self.context
25
27
  position = self.position
26
28
 
@@ -44,7 +46,7 @@ class PysTraceback(Pys):
44
46
  '{}{}{}'.format(
45
47
  '' if is_positionless else f', line {magenta}{position.start_line}{reset}',
46
48
  '' if context_name is None else f', in {magenta}{context_name}{reset}',
47
- '' if is_positionless else f'\n{indent(position.format_arrow(colored), 4)}'
49
+ '' if is_positionless else f'\n{indent(format_arrow(position, colored), 4)}'
48
50
  )
49
51
  )
50
52
 
@@ -120,10 +120,25 @@ try:
120
120
 
121
121
  # Numbers
122
122
  (
123
- r'0[bB][01](_?[01])*[jJiI]?|0[oO][0-7](_?[0-7])*[jJiI]?|0[xX][0-9a-fA-F](_?[0-9a-fA-F])*[jJiI]?|((?'
124
- r':[0-9](_?[0-9])*)?\\.[0-9](_?[0-9])*|[0-9](_?[0-9])*\\.)([eE][+-]?[0-9](_?[0-9])*)?[jJiI]?|[0-9]('
125
- r'_?[0-9])*([eE][+-]?[0-9](_?[0-9])*)[jJiI]?|[0-9](_?[0-9])*[jJiI]?',
126
- Number
123
+ r'0[bB][01](_?[01])*[jJiI]?',
124
+ Number.Binary
125
+ ),
126
+ (
127
+ r'0[oO][0-7](_?[0-7])*[jJiI]?',
128
+ Number.Octal
129
+ ),
130
+ (
131
+ r'0[xX][0-9a-fA-F](_?[0-9a-fA-F])*[jJiI]?',
132
+ Number.Hex
133
+ ),
134
+ (
135
+ r'((?:[0-9](_?[0-9])*)?\.[0-9](_?[0-9])*|[0-9](_?[0-9])*\.)([eE][+-]?[0-9](_?[0-9])*)?[jJiI]?|[0-9]'
136
+ r'(_?[0-9])*([eE][+-]?[0-9](_?[0-9])*)[jJiI]?',
137
+ Number.Float
138
+ ),
139
+ (
140
+ r'[0-9](_?[0-9])*[jJiI]?',
141
+ Number.Integer
127
142
  ),
128
143
 
129
144
  # Comments
@@ -293,7 +293,11 @@ def visit_TernaryOperatorNode(node, context):
293
293
  return result
294
294
 
295
295
  with result(context, ncondition.position):
296
- return result.success(register(visit(node.valid if condition else node.invalid, context)))
296
+ value = register(visit(node.valid if condition else node.invalid, context))
297
+ if should_return():
298
+ return result
299
+
300
+ return result.success(value)
297
301
 
298
302
  if should_return():
299
303
  return result
@@ -588,6 +592,51 @@ def visit_SwitchNode(node, context):
588
592
 
589
593
  return result.success(None)
590
594
 
595
+ def visit_MatchNode(node, context):
596
+ result = PysRunTimeResult()
597
+
598
+ register = result.register
599
+ should_return = result.should_return
600
+ ntarget = node.target
601
+
602
+ compare = False
603
+
604
+ if ntarget:
605
+ target = register(visit(ntarget, context))
606
+ if should_return():
607
+ return result
608
+
609
+ compare = True
610
+
611
+ for ncondition, nvalue in node.cases:
612
+ condition = register(visit(ncondition, context))
613
+ if should_return():
614
+ return result
615
+
616
+ with result(context, ncondition.position):
617
+ valid = target == condition if compare else condition
618
+
619
+ if should_return():
620
+ return result
621
+
622
+ if valid:
623
+ value = register(visit(nvalue, context))
624
+ if should_return():
625
+ return result
626
+
627
+ return result.success(value)
628
+
629
+ ndefault = node.default
630
+
631
+ if ndefault:
632
+ default = register(visit(ndefault, context))
633
+ if should_return():
634
+ return result
635
+
636
+ return result.success(default)
637
+
638
+ return result.success(None)
639
+
591
640
  def visit_TryNode(node, context):
592
641
  result = PysRunTimeResult()
593
642
 
@@ -1,7 +1,7 @@
1
1
  from .bases import Pys
2
2
  from .buffer import PysFileBuffer
3
3
  from .checks import is_keyword
4
- from .constants import TOKENS, DEFAULT, HIGHLIGHT
4
+ from .constants import TOKENS, DEFAULT, SILENT, HIGHLIGHT
5
5
  from .context import PysContext
6
6
  from .exceptions import PysTraceback
7
7
  from .position import PysPosition
@@ -86,6 +86,11 @@ class PysLexer(Pys):
86
86
  )
87
87
  )
88
88
 
89
+ def warning(self, message):
90
+ if not (self.flags & SILENT or self.flags & HIGHLIGHT or message in self.warnings):
91
+ print(message, file=sys.stderr)
92
+ self.warnings.add(message)
93
+
89
94
  def throw(self, start, end, message, add_token=True):
90
95
  if self.error is None:
91
96
 
@@ -111,6 +116,7 @@ class PysLexer(Pys):
111
116
  def make_tokens(self) -> tuple[tuple[PysToken, ...] | tuple[PysToken], PysTraceback | None]:
112
117
  self.index = 0
113
118
  self.tokens = []
119
+ self.warnings = set()
114
120
  self.error = None
115
121
 
116
122
  self.update_current_character()
@@ -385,7 +391,6 @@ class PysLexer(Pys):
385
391
  return self.file.text[self.index:self.index + 3] == triple_prefix
386
392
 
387
393
  is_triple_quote = triple_quote()
388
- warning_displayed = False
389
394
  decoded_error_message = None
390
395
 
391
396
  def decode_error(is_unicode_error, start, end, message):
@@ -516,14 +521,8 @@ class PysLexer(Pys):
516
521
  string += '\\'
517
522
  break
518
523
 
519
- if not (warning_displayed or self.flags & HIGHLIGHT):
520
- warning_displayed = True
521
- print(
522
- f"SyntaxWarning: invalid escape sequence '\\{self.current_character}'",
523
- file=sys.stderr
524
- )
525
-
526
524
  string += '\\' + self.current_character
525
+ self.warning(f"SyntaxWarning: invalid escape sequence '\\{self.current_character}'")
527
526
  self.advance()
528
527
 
529
528
  else:
@@ -0,0 +1,131 @@
1
+ from .constants import TOKENS, KEYWORDS
2
+
3
+ from operator import (
4
+ is_not, eq, ne, lt, gt, le, ge, add, sub, mul, truediv, floordiv, pow, matmul, mod, and_, or_, xor, lshift, rshift,
5
+ iadd, isub, imul, itruediv, ifloordiv, ipow, imatmul, imod, iand, ior, ixor, ilshift, irshift, pos, neg, inv
6
+ )
7
+ from types import MappingProxyType
8
+
9
+ BINARY_FUNCTIONS_MAP = MappingProxyType({
10
+ TOKENS['NOT-IN']: lambda a, b : a not in b,
11
+ TOKENS['IS-NOT']: is_not,
12
+ TOKENS['PLUS']: add,
13
+ TOKENS['MINUS']: sub,
14
+ TOKENS['STAR']: mul,
15
+ TOKENS['SLASH']: truediv,
16
+ TOKENS['DOUBLE-SLASH']: floordiv,
17
+ TOKENS['DOUBLE-STAR']: pow,
18
+ TOKENS['AT']: matmul,
19
+ TOKENS['PERCENT']: mod,
20
+ TOKENS['AMPERSAND']: and_,
21
+ TOKENS['PIPE']: or_,
22
+ TOKENS['CIRCUMFLEX']: xor,
23
+ TOKENS['DOUBLE-LESS-THAN']: lshift,
24
+ TOKENS['DOUBLE-GREATER-THAN']: rshift,
25
+ TOKENS['DOUBLE-EQUAL']: eq,
26
+ TOKENS['EQUAL-EXCLAMATION']: ne,
27
+ TOKENS['LESS-THAN']: lt,
28
+ TOKENS['GREATER-THAN']: gt,
29
+ TOKENS['EQUAL-LESS-THAN']: le,
30
+ TOKENS['EQUAL-GREATER-THAN']: ge,
31
+ TOKENS['EQUAL-PLUS']: iadd,
32
+ TOKENS['EQUAL-MINUS']: isub,
33
+ TOKENS['EQUAL-STAR']: imul,
34
+ TOKENS['EQUAL-SLASH']: itruediv,
35
+ TOKENS['EQUAL-DOUBLE-SLASH']: ifloordiv,
36
+ TOKENS['EQUAL-DOUBLE-STAR']: ipow,
37
+ TOKENS['EQUAL-AT']: imatmul,
38
+ TOKENS['EQUAL-PERCENT']: imod,
39
+ TOKENS['EQUAL-AMPERSAND']: iand,
40
+ TOKENS['EQUAL-PIPE']: ior,
41
+ TOKENS['EQUAL-CIRCUMFLEX']: ixor,
42
+ TOKENS['EQUAL-DOUBLE-LESS-THAN']: ilshift,
43
+ TOKENS['EQUAL-DOUBLE-GREATER-THAN']: irshift,
44
+ })
45
+
46
+ UNARY_FUNCTIONS_MAP = MappingProxyType({
47
+ TOKENS['PLUS']: pos,
48
+ TOKENS['MINUS']: neg,
49
+ TOKENS['TILDE']: inv
50
+ })
51
+
52
+ KEYWORDS_TO_VALUES_MAP = MappingProxyType({
53
+ KEYWORDS['True']: True,
54
+ KEYWORDS['False']: False,
55
+ KEYWORDS['None']: None,
56
+ KEYWORDS['true']: True,
57
+ KEYWORDS['false']: False,
58
+ KEYWORDS['none']: None
59
+ })
60
+
61
+ BRACKETS_MAP = MappingProxyType({
62
+ TOKENS['LEFT-PARENTHESIS']: TOKENS['RIGHT-PARENTHESIS'],
63
+ TOKENS['LEFT-SQUARE']: TOKENS['RIGHT-SQUARE'],
64
+ TOKENS['LEFT-CURLY']: TOKENS['RIGHT-CURLY']
65
+ })
66
+
67
+ SYMBOLS_TOKEN_MAP = MappingProxyType({
68
+ TOKENS['NOT-IN']: KEYWORDS['not'] + ' ' + KEYWORDS['in'],
69
+ TOKENS['IS-NOT']: KEYWORDS['is'] + ' ' + KEYWORDS['not'],
70
+ TOKENS['NULL']: '\0',
71
+ TOKENS['NEWLINE']: '\n',
72
+ TOKENS['EXCLAMATION']: '!',
73
+ TOKENS['COMMENT']: '#',
74
+ TOKENS['PERCENT']: '%',
75
+ TOKENS['AMPERSAND']: '&',
76
+ TOKENS['RIGHT-PARENTHESIS']: ')',
77
+ TOKENS['LEFT-PARENTHESIS']: '(',
78
+ TOKENS['STAR']: '*',
79
+ TOKENS['PLUS']: '+',
80
+ TOKENS['COMMA']: ',',
81
+ TOKENS['MINUS']: '-',
82
+ TOKENS['DOT']: '.',
83
+ TOKENS['SLASH']: '/',
84
+ TOKENS['COLON']: ':',
85
+ TOKENS['SEMICOLON']: ';',
86
+ TOKENS['LESS-THAN']: '<',
87
+ TOKENS['EQUAL']: '=',
88
+ TOKENS['GREATER-THAN']: '>',
89
+ TOKENS['QUESTION']: '?',
90
+ TOKENS['AT']: '@',
91
+ TOKENS['LEFT-SQUARE']: '[',
92
+ TOKENS['RIGHT-SQUARE']: ']',
93
+ TOKENS['CIRCUMFLEX']: '^',
94
+ TOKENS['LEFT-CURLY']: '{',
95
+ TOKENS['PIPE']: '|',
96
+ TOKENS['RIGHT-CURLY']: '}',
97
+ TOKENS['TILDE']: '~',
98
+ TOKENS['DOUBLE-AMPERSAND']: '&&',
99
+ TOKENS['DOUBLE-STAR']: '**',
100
+ TOKENS['DOUBLE-PLUS']: '++',
101
+ TOKENS['DOUBLE-MINUS']: '--',
102
+ TOKENS['DOUBLE-SLASH']: '//',
103
+ TOKENS['DOUBLE-LESS-THAN']: '<<',
104
+ TOKENS['DOUBLE-EQUAL']: '==',
105
+ TOKENS['DOUBLE-GREATER-THAN']: '>>',
106
+ TOKENS['DOUBLE-QUESTION']: '??',
107
+ TOKENS['DOUBLE-PIPE']: '||',
108
+ TOKENS['TRIPLE-DOT']: '...',
109
+ TOKENS['EQUAL-EXCLAMATION']: '!=',
110
+ TOKENS['EQUAL-PERCENT']: '%=',
111
+ TOKENS['EQUAL-AMPERSAND']: '&=',
112
+ TOKENS['EQUAL-STAR']: '*=',
113
+ TOKENS['EQUAL-PLUS']: '+=',
114
+ TOKENS['EQUAL-MINUS']: '-=',
115
+ TOKENS['EQUAL-SLASH']: '/=',
116
+ TOKENS['EQUAL-COLON']: ':=',
117
+ TOKENS['EQUAL-LESS-THAN']: '<=',
118
+ TOKENS['EQUAL-GREATER-THAN']: '>=',
119
+ TOKENS['EQUAL-AT']: '@=',
120
+ TOKENS['EQUAL-CIRCUMFLEX']: '^=',
121
+ TOKENS['EQUAL-PIPE']: '|=',
122
+ TOKENS['EQUAL-TILDE']: '~=',
123
+ TOKENS['EQUAL-DOUBLE-STAR']: '**=',
124
+ TOKENS['EQUAL-DOUBLE-SLASH']: '//=',
125
+ TOKENS['EQUAL-DOUBLE-LESS-THAN']: '<<=',
126
+ TOKENS['EQUAL-DOUBLE-GREATER-THAN']: '>>=',
127
+ TOKENS['EQUAL-ARROW']: '=>',
128
+ TOKENS['EXCLAMATION-TILDE']: '~!'
129
+ })
130
+
131
+ EMPTY_MAP = MappingProxyType({})
@@ -1,7 +1,7 @@
1
1
  from .bases import Pys
2
2
  from .position import PysPosition
3
3
  from .token import PysToken
4
- from .utils.decorators import typechecked, immutable
4
+ from .utils.decorators import typechecked, immutable, inheritable
5
5
  from .utils.generic import setimuattr
6
6
 
7
7
  from typing import Literal
@@ -15,6 +15,10 @@ class PysNode(Pys):
15
15
  def __init__(self, position: PysPosition) -> None:
16
16
  setimuattr(self, 'position', position)
17
17
 
18
+ def __init_subclass__(cls, **kwargs):
19
+ super().__init_subclass__(**kwargs)
20
+ inheritable(cls)
21
+
18
22
  def __repr__(self):
19
23
  return 'Node()'
20
24
 
@@ -342,6 +346,27 @@ class PysSwitchNode(PysNode):
342
346
  def __repr__(self):
343
347
  return f'Switch(target={self.target!r}, case_cases={self.case_cases!r}, default_body={self.default_body!r})'
344
348
 
349
+ class PysMatchNode(PysNode):
350
+
351
+ __slots__ = ('target', 'cases', 'default')
352
+
353
+ @typechecked
354
+ def __init__(
355
+ self,
356
+ target: PysNode | None,
357
+ cases: list[tuple[PysNode, PysNode]],
358
+ default: PysNode | None,
359
+ position: PysPosition
360
+ ) -> None:
361
+
362
+ super().__init__(position)
363
+ setimuattr(self, 'target', target)
364
+ setimuattr(self, 'cases', tuple(cases))
365
+ setimuattr(self, 'default', default)
366
+
367
+ def __repr__(self):
368
+ return f'Match(target={self.target!r}, cases={self.cases!r}, default={self.default!r})'
369
+
345
370
  class PysTryNode(PysNode):
346
371
 
347
372
  __slots__ = ('body', 'catch_cases', 'else_body', 'finally_body')
@@ -19,10 +19,11 @@ class PysCode(PysObject):
19
19
  class PysPythonFunction(PysObject):
20
20
 
21
21
  def __init__(self, func):
22
- from .handlers import handle_call
22
+ from .handlers import handle_call # circular import problem solved
23
23
 
24
- self.__name__ = func.__name__
25
- self.__qualname__ = func.__qualname__
24
+ self.__name__ = getattr(func, '__name__', '<function>')
25
+ self.__qualname__ = getattr(func, '__qualname__', '<function>')
26
+ self.__doc__ = getattr(func, '__doc__', None)
26
27
  self.__func__ = func
27
28
  self.__code__ = PysCode(
28
29
  position=None,
@@ -46,7 +47,7 @@ class PysPythonFunction(PysObject):
46
47
  class PysFunction(PysObject):
47
48
 
48
49
  def __init__(self, name, qualname, parameters, body, position, context):
49
- from .interpreter import visit
50
+ from .interpreter import visit # circular import problem solved
50
51
 
51
52
  context = context.parent if isinstance(context, PysClassContext) else context
52
53