cpyte 4.6.0__tar.gz → 4.6.2__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 (52) hide show
  1. {cpyte-4.6.0/source/cpyte.egg-info → cpyte-4.6.2}/PKG-INFO +3 -3
  2. {cpyte-4.6.0 → cpyte-4.6.2}/pyproject.toml +1 -0
  3. {cpyte-4.6.0 → cpyte-4.6.2}/readme.md +1 -2
  4. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/__init__.py +5 -3
  5. cpyte-4.6.2/source/cpyte/_bignum_bc.py +179 -0
  6. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/astparse.py +100 -3
  7. cpyte-4.6.2/source/cpyte/bignum.c +323 -0
  8. cpyte-4.6.2/source/cpyte/bignum_protos.h +109 -0
  9. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/bytecoding.py +231 -28
  10. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/compiling.py +209 -15
  11. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/extension_hooks.py +471 -44
  12. cpyte-4.6.2/source/cpyte/floats_runtime.c +598 -0
  13. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/generate_bc.py +11 -2
  14. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/lexar.py +29 -0
  15. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/linker.py +2 -0
  16. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/mainpie.py +61 -16
  17. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/package_manifest.py +86 -12
  18. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/runtime.c +22 -4
  19. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/sef.py +39 -21
  20. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/semantic_analasis.py +187 -98
  21. {cpyte-4.6.0 → cpyte-4.6.2/source/cpyte.egg-info}/PKG-INFO +3 -3
  22. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte.egg-info/SOURCES.txt +3 -0
  23. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte.egg-info/requires.txt +1 -0
  24. cpyte-4.6.2/test/test_compiler_regressions.py +289 -0
  25. cpyte-4.6.0/source/cpyte/_bignum_bc.py +0 -355
  26. cpyte-4.6.0/source/cpyte/bignum.c +0 -728
  27. {cpyte-4.6.0 → cpyte-4.6.2}/MANIFEST.in +0 -0
  28. {cpyte-4.6.0 → cpyte-4.6.2}/setup.cfg +0 -0
  29. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/__main__.py +0 -0
  30. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/_runtime_bc.py +0 -0
  31. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/clib.py +0 -0
  32. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/elf2sef.py +0 -0
  33. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/formatter.py +0 -0
  34. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/gc_runtime.c +0 -0
  35. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/lsp_server.py +0 -0
  36. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/mksef.py +0 -0
  37. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/optimizations.py +0 -0
  38. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/runtime_scorpion.c +0 -0
  39. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/scorpion_abi.py +0 -0
  40. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/ugc.h +0 -0
  41. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/ui.py +0 -0
  42. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/update_check.py +0 -0
  43. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/winjit_patch.py +0 -0
  44. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte/winjit_stubs.c +0 -0
  45. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte.egg-info/dependency_links.txt +0 -0
  46. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte.egg-info/entry_points.txt +0 -0
  47. {cpyte-4.6.0 → cpyte-4.6.2}/source/cpyte.egg-info/top_level.txt +0 -0
  48. {cpyte-4.6.0 → cpyte-4.6.2}/test/test_bignum_jit.py +0 -0
  49. {cpyte-4.6.0 → cpyte-4.6.2}/test/test_fuzz_del_has.py +0 -0
  50. {cpyte-4.6.0 → cpyte-4.6.2}/test/test_scorpion_abi.py +0 -0
  51. {cpyte-4.6.0 → cpyte-4.6.2}/test/test_scorpion_dl.py +0 -0
  52. {cpyte-4.6.0 → cpyte-4.6.2}/test/test_sef_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cpyte
3
- Version: 4.6.0
3
+ Version: 4.6.2
4
4
  Summary: The Cpyte programming language compiler
5
5
  Author: Hoang Duy Tung
6
6
  License: MIT
@@ -8,9 +8,9 @@ Requires-Python: >=3.11
8
8
  Description-Content-Type: text/markdown
9
9
  Requires-Dist: llvmlite>=0.45
10
10
  Requires-Dist: lsprotocol>=2025.0.0
11
+ Requires-Dist: pygls>=1.3.1
11
12
 
12
- DEVELOPMENT IS CONTINUED. WINDOWS SUPPORT IS IN PROGRESS.
13
-
13
+ NOTICE: It seems cpyte has been going through a lot of changes, including the OOP work which was quite fabulous and python-like. I liked how the syntax changes very interestingly and made the language better. However, as many changes are breaking-change and usualy a prone to error, I've decided to finalize a syntax-lock, in just a 2 months. After that, improvements will be delivered through the @std/improvements package with the extension hook framework.
14
14
 
15
15
  Check out the official documentation [here](https://gitea.5gnew.io.vn/Cpyte-Project/Cpyte/src/branch/main/source/cpyte/cpy_language_documentation.md).
16
16
 
@@ -16,6 +16,7 @@ authors = [
16
16
  dependencies = [
17
17
  "llvmlite>=0.45",
18
18
  "lsprotocol>=2025.0.0",
19
+ "pygls>=1.3.1",
19
20
  ]
20
21
 
21
22
  [project.scripts]
@@ -1,5 +1,4 @@
1
- DEVELOPMENT IS CONTINUED. WINDOWS SUPPORT IS IN PROGRESS.
2
-
1
+ NOTICE: It seems cpyte has been going through a lot of changes, including the OOP work which was quite fabulous and python-like. I liked how the syntax changes very interestingly and made the language better. However, as many changes are breaking-change and usualy a prone to error, I've decided to finalize a syntax-lock, in just a 2 months. After that, improvements will be delivered through the @std/improvements package with the extension hook framework.
3
2
 
4
3
  Check out the official documentation [here](https://gitea.5gnew.io.vn/Cpyte-Project/Cpyte/src/branch/main/source/cpyte/cpy_language_documentation.md).
5
4
 
@@ -1,4 +1,4 @@
1
- __version__ = "4.6.0"
1
+ __version__ = "4.6.2"
2
2
 
3
3
  # ---------------------------------------------------------------------------
4
4
  # Public library API.
@@ -38,9 +38,11 @@ def parse_and_analyze(
38
38
  workspace_root = mainpie._find_workspace_root(filepath)
39
39
  if enable_extensions:
40
40
  mainpie._load_package_manifests_from_source(workspace_root)
41
- lex = lexar.Lexer(source, tab_size=tab_size, enable_extensions=enable_extensions)
42
- tokens = lex.get_tokens()
43
41
  try:
42
+ lex = lexar.Lexer(
43
+ source, tab_size=tab_size, enable_extensions=enable_extensions
44
+ )
45
+ tokens = lex.get_tokens()
44
46
  parsed, _ = astparse.parse_file(tokens, enable_extensions=enable_extensions)
45
47
  except (lexar.LexerError, astparse.ParseError) as e:
46
48
  raise CpyteCompileError(f"parse error: {e}") from e
@@ -0,0 +1,179 @@
1
+ import base64, zlib
2
+ from llvmlite import binding
3
+
4
+
5
+ _B64 = (
6
+ 'eJzten14E1Xa/plMmgltOglQIKVJmABiVT6mKWD6pUlToCpqQFxx1U3SD2hdStO0lNLV3UxTmqrVDVi1'
7
+ 'P9d1W2F9wf2wsl0vVlk3aSpWqFhd1MqybAoFC4tQAXfZj9/u+5yZSZNMcK93972u9y9LSc/c88yZ+zzn'
8
+ 'ee7znJmcCM5KQ/CTAf8fWYPQP+Gn2BY8sQyAFMDKVOz82+9/6+Wav/3y7rQ13tUEYEYVQh/RCKXJjEgG'
9
+ 'x3PhP8XN22EdlN+m0JjydhKtqutSlJkG+RNlXu0KWfHOtOIBjSnDrNTekWoqay/trTDa2trlq3Sm4vl1'
10
+ 'g8qp82+wtHVo7iBMFa3KnTpm3sr20ygzp1ieeWP2jYE1DzLzfmVpU2WGqcMzMss6OuZTmaayhXmDganz'
11
+ 'Bqe10/r8ipJVg5q5tpWyzNnoMQahbMxpg1yzr7jlsalr4WNHXb+9NHXKgpUHU4rLFigPes8oA51T9s0d'
12
+ '9HXLg0rLVJXzKZTxOGJWIK9Ji0yrkGK7E3lvIBGqZFG3RgF/nfAXBdEKi9fEorVKEgVatKifUck6OZd3'
13
+ 'rnb1VK3zKSabDFf9mEXog9udKvlulJvifnrpik72L/98v/DTJXdOvW51lVPLkMXY32u0CD0EDs4av+4q'
14
+ '9jkRaGGVyvqA313l91SRTU3+BjfVnE1tQ8dH9cd70kd6dP0hHerXn+hJH7ca+glDxKg/Pqo71q3v5wzD'
15
+ 'RDe1bY/fg9q3dfvdWv8W6CHg39rt92ip5iZqWxVZt4eqZ/2egH95l79hGCwnEDNu1I2N6g5xhmNOXaTH'
16
+ '4HV7qSYn3N3X2E56oZ+Avz6baq4i67P97m5/c8Dv6aKc6f09ujNc+seMboQzHLfOORgyjDjTBzjDhwA6'
17
+ 'dQc5XURoGPWDxBw4ddClixDY5uCo/hg0iDnHewzHeJsxlw7wQaN+HA69uhOcIWI1nOAwOMTp+2F0gAeB'
18
+ 'W3q/1XAsZJjw8odG+nwQTumxGWEYH9V/GOJ7COrOARjiDcDSoj/j0p0I6c/jzvVnenC3x3swAo2IEYwN'
19
+ 'w3AKGQ5ZDUM9ehG3Gg5xujFhjBZDvwszB54RnuoYx1NyGgb4z2FwoFdsnOEbkR7dQejBZYA5+tClG+fN'
20
+ 'zlj53oKGiWD6SQb3c55QH7fQ/VHwzCTojYHnomA/MWJRIktqVrsRlbrCb2pwvNyqOcOoR4fp08OKiQn6'
21
+ 'bIS+Yqcvof3hgv22rF5bXqsvD7UWHLBlDfsKW8nCoC1/fzivz1rQShZ1kxb1Jbv6NNJctqhHWfqP0AOj'
22
+ 'vmhRn2bpKxP0pWHFSbv6jJM+zahrWPXZbrCMEJZhm3kwnNdJFvWFzEFbERpF6okgvvvnGgpZ1aOM+jM7'
23
+ 'fWVYccZOj1rUXzLQmzo4u9WWN0Rm/dRq7iWL9vtu6fAV9YZmt5NFuwEMmTvIvKDQsOUHyFvgVEfYHCQL'
24
+ '+UZBHzTIW/bbivp4m8GwGfCALX8YDom8A2RR0Fd4gMwDsIssaIXRAc7lBW1Zrb7CPl9RhBAOIUzhVAFv'
25
+ 'VjgcLtjtKxjmLY8C6OMNsGX+UNh8wFcwgjsvGLLhbvfb8gCBRtBmPor9BqcKO32FXbYCEfcVdpJ5g8IY'
26
+ 'ucLWMGYOPIM81UGSpxQqbOc/u8GBhNgY4htBW14H9BAuhDnaHTYP82ZDPjPfW1GEyxqw4n5GSMN+Ttca'
27
+ 'BYcmQUI/CR6Ngq1kL7HhcRwgc9A9aH63WnY/I3ugyaqR41870w8JMqo/2JM+ZNQdM+pHjHO8jUqq0enf'
28
+ 'qqW8LLVN6W/M9i/3+reWUlg9AlQQ58Uxr/6QUTdEMKBFx7yGMSPOaEi6Iz3px4y6cUKPQBxArLxdVLPS'
29
+ 'X7ceeqC2NYF8+eu6/VtBczT+ZpYCMdlW5dtWSj2aTSE1ajFAUh/p0Y33pB8kDOcIJdXkpfDdq/xmpGxW'
30
+ 'UtvMfk+3fzmolpJq3kNty/ZvQyA7h/iUhIGMh/RXXDqc3RbduFEvSM2gIDUu3YecbkIQIpBKvnGiRx/h'
31
+ '9BMh/bke3thqOMjLzoccvmRwVD9OGMZG9YO8kowYdUd6RIU5xoAg6CEThcOTQRrkYkSQJs5wAnSY72Go'
32
+ 'xzDC6QUDODzqMoDiHeflccQFqgL2+kOA8JrT32MAv2HB6dGNhXTHojgozyAvIFhtjKIKwRAO8o1BnhLo'
33
+ 'Cf4k9P1WWmy4hAZcKGgXzJH+IM/qjMswwPeG5YWJycvYpOY4Y+D4JNgdBRmdN/2xqeg1FCh20kHFSQ1a'
34
+ 'O2JhSJCjjvmolNizXPs4CsjsNcPPncZhRwUz0K184D2w56No1A3BgtWjP9STHhG0GoZMuP1b3f7lTjy5'
35
+ '9Ui5tcm/HJYwHAOw8PnrYQ2CSbdQEGw9hkMEAyPqd+k+7knnFwg8TJD9sZ70gR7DUEgHAn7MafjQOucQ'
36
+ 'EYxfuXx1Xn8zwmslh+9+zEjHR90QLKmc4Rzvbe8yJV7dlq/3uZ1Us5t6VEt9x+lbpqGaSzFYp6U8XqHh'
37
+ 'b2CoR+CU1l+Hl0vc2FoFDeoRt7+5ircJ+OsAZ/wN3XBIeiAR+HTwAMhSjUoYHcbrvf7lEORV1HeCpHAI'
38
+ 'KgmnGnmzpm4hB3nLPQBSggEcbuny1zVRW3vxqcYuP+7W7Ye7bIWG1+/eg/0Gp5og3Vh/o4hD+lCegDBG'
39
+ 'EtJ8G4DA08tTDVAenvk2Df9pAQeSYqOLb3hxIYETEOaoFJKaN+ui6vjegP/N7eA337JeqtBN5imjYFcM'
40
+ 'zJ8E90RBJeUkf8Pyaxl6Gb0gi1Be+RWrM82obGHwb2orSKu5z5bXRxQegPWLLALtRRcm6AvDivOwyjhp'
41
+ 'NEpfHFZcgXUQFqMAfcFN1wzj1WccgaIeteWhgUJYtjrC+dDDYLhgGPSWLDoAqwNnPurL67JB/1lDtvxx'
42
+ 'sGxCmisa+pKbPm2BVY+esKst/Epkw4vmQPzyx+V12szDtiJe9nsVo3b6clDxbQ193qK+0K0+5VRv6lWc'
43
+ 'tKjPAsjSpyz0hNAI0GNefOoUdI74xgT9OVKf96ov2NWf8zaXWBrwsQB9BQ4tNKzI/LqMwTNBetRNYzMn'
44
+ 'PTGsgNX2c6e6STjUQHDAKd4Mqa8IxQB/6ssgfV4wgMNu+jJLX4zQf4J2kL5sx/YX7BiBxoSG/hL8BqeQ'
45
+ 'Gtb9M8NRHNZxC31JGCP4mcXMgecET/WShafEqk/yn+Ma2hNt1PONCTt9iq8EYI7OsjwrVn2Z4XsD/hFF'
46
+ 'nQb38ycvtZmhRqNg/SRoiYFbouAo2mR+HjHbg6BLy079HccP6hKDh0m7jaX4iJK/HhSiqKXb0goLfbig'
47
+ 'w5bVhcMpv9d2C/oc5itIX2Rp5KIvaejP7XQNUl+EELLg4Xvx+t5HFMBEd5EWqKn6CJhuHA9QPLxgy+qD'
48
+ 'ACDzEQzqSzuNctQQOad6cQ+XJnAZdsqivgi1E0N/6aShHIKC6nKA/itYGpC8CIqTF2x5w7asDrLwKKnB'
49
+ 'wQDBDHFbFx+BUH1poCs19jyC8qmTLy1gIMO+gvGwGVcpHARhvlAyBcSSybybzIuIlVWhUFkdsBUEyYKI'
50
+ 'r+CoDVcsUG908OXTbhJXYgFIChKnRoCviHpt5hdsYqXUZzUP2qAcMgiHA5weyp5eocSCJOLzEZ+yFfWS'
51
+ 'BYIBHO4JF0Lltp8v83rDUB2BfUEnIHzt1GorAr/xBVXeoC+vL4pDKgX4QghXTTah/gGePFWuMMBTgroI'
52
+ 'f5L5rT6d2AgLDbjQzCcjzFF+B89qKFzYzveGyyRrrHYanKydQjFweBK0RgsqqxlldVBomjdj+XjaFRxQ'
53
+ 'pEXhJUq8Ga1WSxdU1DaIjaygUEzCWMgIzpeaIJ61M0gDGlUDNTY/uZCMn+Eimb7ipREwLOokLUC1NWz+'
54
+ 'KfSAK9gi4A91KWhRu62oy5cHKtcXgki7pZP0JpTWp5D6S4SLeRLfvc+miw8nUDOo7Y/ybkQgR6f5VB0N'
55
+ '0lci9F9ZPusZ+kqAFiRoDIladNZCXxUECtfzuHFxGCSLvhqhvxzmjRn1KV6OzlrwJWMQ4Xycj/EKc14D'
56
+ 'oxOVpwaid5iGDBUO65wUyMh5QaMsYnLhU3Y1pJ5gAIfnWDUo4QVeNs+z6tNgH6FPA8Jr0ahdDX7DQgR5'
57
+ 'BCoXxSEvxnhhwSqkEdUJhnCKb4zxlEBn8KeXHmUoscHyDYR3OjizYI4COFsxCCLG94ZlRxOTHc+kFrEx'
58
+ 'sGEStEdBDR1smz8NrUWvBHUvpbeWoN29XFcqxI+mkwj0K17Kh6qJXfIxDiW1dw6a9rXsfC0715Sdp+5A'
59
+ 'pUaWcoYPOIXS6Luo5OtC6OtC6JqFELtP2OnfinanPzYT7UbruDyU9dLn/EYsgjdi/0ABbz76K9ObIuzF'
60
+ 'NPLt6fLr0SO9PWf/AUbfQ3cRE6RFBgbbp04aPDYLTbFQuKudd6Np3alDxIjFSxATobbrVbGrImo0ZdwX'
61
+ 'nLlS7DljeUaZRn4Gbco+GMEE/E6aNx6xBwjNHqKPy/YJbDeSLoUQ2x8qTqlk3gxv7oizO0QEZG5FVsdS'
62
+ '2GCiI05fjwL2mMHMTaUf871RAslvpkdJUlnyYKa8WrOp9BgD+1Czj0lvSX8sS45uQBs18lDbWLoc96xs'
63
+ 'cZIyoSZEFajEK0cI3aZFyAR/p7dauhh5WM5pFyi357iUra5+i+odeYuWrpBNVYYBmVbZ3wsIV71AdSR3'
64
+ 'tabbBbhtKWFsI3cseOV5y/p+952aXld/YMoxuevUAs0P/8yFWtHzTCunXa096FW1TbFmrtYMRVQL5BtZ'
65
+ 'IseXa9ZUvzTslLkUGwOKwdaQ6kiki+0KZe4OyftVR5j0o87+Xnxqumx5l6Ur5N4TkodUx5wtrCLc2q86'
66
+ 'HknXVGMD92rtkNO8ABhavT4CxtELG97GXjK/yhd7hKuETaJ/W5DK6yVv9sKvL/2/eMFvnsBLhsdNubup'
67
+ 'eoZqZikPfgBIbdXwbR4UDKDdaKGanVTDsOIsfPKHNQG6joHdKYU/hxUXWNGshk0TkJcjNPRwu1o5dae1'
68
+ 'rSMjk1ha3PXCx6Gf5C85/NmrjebPv2u9XN6w/kTboT+cu9R1y/ceeuKTT/7+0HPfP/xqTuHdS34zcPYX'
69
+ 'b55ofHKr3WtUXQzAZOH54ggUpA+xbYRhJ0JeABgWoRFrzhQGIYIHEMzo+e5XOO1J4xSElADISOQ1zng5'
70
+ 'Q+gBv6VASMHunuY7jZAF2hoeYb3Ge7NYSoNIoWP4JFR7L3nNXgR985cipHKWfkTdLUMWcDXDI05ku/Eb'
71
+ 'gWkIpSLMAP+Q2rV/6d+FkB0J9wdKwcAr+udTlLhvC48EUdu6v0aWWpAunlLxlLcJvpdJSs+szlZrkCKe'
72
+ 'UlMx50XmeEqVMx8n+V5ilPbbGQbR8ZTObj8p9DJJ6fGlGUqlN4HSz3vMQi+TlPqfVMhkkQQvbbPQfC8x'
73
+ 'Sud2SSldNzeJ0sz7aQaPJEbp96UkQbgTKK3OSEFeWTylzS+VIDQ/gdL062QyS4KX9rAUbxCj9ODbOySU'
74
+ '3r7pScnEvdKQs4BBM+Mp/fqJHYgIJkzctzIovpcYpX9eKrTgMItR8vy/Ngmlj46UztAgKp7SsQ11Qi+T'
75
+ 'lLbfPMghGyleRmAvDd8/F6Fp8ZR+dkQ6cYcakyYusks6cWvnpEgmbsb/XyiduH+skk7cM8VPQLqQ8RM3'
76
+ 'u/lGSSw9+QFQiiRQenJ3qoRS99H1FlQYT+nhH8+TyYIJlBbNmKXBhzFKnseCXtQeT+mjO0oUcqzWsYlz'
77
+ 'ly1n0AIU/QFKv7znbYKwEFEEKN2++yUataWKgAxTyq3cgth1IqLBlG6/6Sekt0dgCCTwxDkq9Ug1QzSS'
78
+ 'Y0ruw+eQc4+IMJjS6W+toZAtRYTwxL3yz8fzkfZGEVFiSqH1R4mgXaRkwZRuHEqi5JkppTT7l3sklGb8'
79
+ 'bIWU0qFFUkqVtUmUnn5CSmn0wSRKn/9cSql7q5TSG7+WeumZvyVR+scSKaUUnzXpdiqfdHTP6BRJzNeo'
80
+ 'khzVpy1JckJOu3SAn5Yzegn54nctUmI/fpqTEnt8EblXSsyhWCshduOIareU2MnMJGJncgNSYs9UMUle'
81
+ '/SCJ2DMvJxF7+O4kYvf+JInYK470JGJfzF4Py9lMEeKT667l3SDCC6MQIgMjjN18lEBMmpxfikyGLl3m'
82
+ '1NWBjikLVh2U24pXotQepv2GlmnZrS3Z1LSl9LmTVzLXbX36sCf3b49+wo2d3vbDO6lfv9e97aHVz/nf'
83
+ 'uXLld+m3v2+9cClv9d2/O7w0+7q7fvTbzW/QGRt+8YfyQN4LG557t2QP5/nk0/MZj5ZP+SYe5Wsgo2fg'
84
+ 'b67SqxsY1W3IIIrabebWcEcx/5y8vqtOBQW88MwkV1Vs6MdvmnQb2BTezJfF77mKYAsz1NTR4Ka+o8QP'
85
+ 'pd1uqtlNNjb53Yw/c2gqfT4A+331Zv7xApTfuZoB/QmjbsSo73cZNrCP4b027IP6yMID+A1pwdBERqOT'
86
+ '+k4VdTN+/07d7MUvEdxOqjGbaryaAt1u9fodUFNp/Z4u/7YubiHef0X4nQVLlg324NcuQ/zncZfukFEH'
87
+ 'G9NDLsXHAby3EnZYefvDZtgxtZOwM10CN/17SwF+BRlWvVPtd6/3e9y+Bvwewd+g9Td0+zOP3KO+IDzo'
88
+ '4J9RjDI07PVymWz8RqnfavjQqDvOGY5HdGOj+nOEYYN2jbnXlv+Cr2DIPl8ciNO/tYlq6lqz+koAb0By'
89
+ 'DQ/z702M+I3edwn8pmnIqJ9wKdZt95mHwgW9sE225f29v3DMVtAOh+GOt1NhpP6twEeJv4rg6eIePMU/'
90
+ 'OD0N+yB2XuhDq2FsdNbIqP4EECjNLOj1FfX5slrD5g7YEoYL94fyYLN5lCwcKu2rwy8ZqTr+5WDm7w7C'
91
+ 'dkz9eYTfVbF4n/UnO71ZQ8OWEA4vRxSwcRuz01fZeSfPu3T8K8tZ5436M0b9AH5lqR83ztnA/LDggK1o'
92
+ 'P5nX6csbWn8AZh8G2ww8S/F7pczDn9EXWfVoBD+2wq+w2TCBX6PAWBxdECrYw/hbEF1cqzUvEgbXFcFM'
93
+ 'DVkGuvWHevT4HVNIt2F+OUuP4vlVn8Uvx21G3xYtVV/qd3T7H/HCta91EoUdYfwcYNiWD+E0BB5TlRpn'
94
+ 'FLsMQPVISL+Wy9iweiNsNmH3GlFctKuv4K7o0xGF+O6e3WXxNVbht66Za2fvDxdAHO62mYfAhyR+NDFE'
95
+ 'FoIzO8OqlekHIXTxOyzddznDJfya7+BrCohA6AfmInfacq0fKn/xJWlXqA+/cC84EDb/XVZ0IJzfCdyq'
96
+ 'jjP8ty+M+oPgwFA6nn1X22XFuJ0eRWo8zAnwPz9StI1BaBPk505DKWNrV2VOqagYfJfhOuSmlStXTueK'
97
+ 'uwNfDAwq84rbOl4KHwBBemKn7r2s+XfLVe8Uo3tK7mC+Uempr67dvLW8yuVx1Fc3V9pvszGrKxsrN23Z'
98
+ '2uAq21S5weOqqVzkrq3e3FDpsbrdmyqZ8k2uzRuZRuFKxpSzmF3MMtk8usiUw7KLc/A/NueGTbVghz9q'
99
+ 'azZXu2sbKjc3MPhG91TX4H5sS2w33cSsK7ZaoXN3Dm/p2ryNEW+GD9GZIkEI2Zbg7rCyf5Z6nrIjv4Nh'
100
+ '/whAb1gp+y09T9me18Ewn7Et3u6wKjzdkqvawbzHrg7nhi1TP1CR95bkyg+qrKawt+kjVfiLe3NVTqSA'
101
+ '1iVovXffeyxbbn/PnV1mf4xbofhEZcts55aF7YoK93us2bEs7FVU2X+vaOe0yb/rn4XPLGh0Ezftx40O'
102
+ '+YLsecuXv7n8uddv3pf/umlW7uu9v/jVmsfTDvctmsHjS/eZbn5jjQxqtb2gqzfDuNJSPdmgV1TzencX'
103
+ '5AgO77zhcMsZ3UHhu0MhnEqCDsxcespJf2bHD5nHLNFHzb1eDgcSVr8mf52Q++vdL4TNfUTBbl9RZ1j2'
104
+ 'bfx+/Pio7jiDv8MDn+P8+9nhHt2gkLCuEIGfdQjPb9PahcRJeZ//igWIYRjStqCDfww1SBYszIZLPoTe'
105
+ 'XKES/AQS5O6sUz0Kn/wzrssB9ecMfTGIq1H0AdSNeD9BDfFPRUFMyaJuXyEIayCM1xZXNkJq+DtP2dZr'
106
+ 'QUId2pqhJObBX5vq8ZvkIWZHilUhuyozasssTkap+L0haFSsmNnidF9pGebrT9xHWlwfuF95B0JrlcHr'
107
+ '5SGNb26alTWfcGnL7FVGpcJfoLrLyV9TxF8T4K+R8/ctnXIU5cxDyyxBXDSXz9Ws1Je6Vsv795A3DA6w'
108
+ 'DovcpkpF8lAk2Do3u6LdWred0c5/IzDYjX7EwimlSh7qTksxD3QPFmtUT3k0bdqFWcoW7sepLZ71ypWq'
109
+ 'nGykkfvmzTvOsQvatBlI2RJ6LfNt5aDGdzLVypY2czsI2Vv9yjatRqtssd6X6m637oA76MYZVc765Ro5'
110
+ '+ZMZrSvffTY9s8yOwBGUf4Bq6d7hzdw7pbhbFXK/401FszN2pRBlSPgu4ANtc5FvkS3DG3rWlXbIeXg4'
111
+ 'pRJF/TUnzl/RsWvuIefxjouNvd1KeIHBvfYWH9D/OdAfm6nKVEXSWp3tBMcx2oZHkV+bcT8MxUj3a3yV'
112
+ 'pJXtvctq7ti7p82oSEEwS+tt02UD/Lw+oDDizfUkh/k8h6cmOWR0IM1aZiBjRbqGxfajLiEestou/gTF'
113
+ '4uG1lOJrx0Orj9lBPPK2JjBfaSoN3qeBqffB1Fed7FmvyWQiN3U427kPwKELr7grjlSt8kZ3hw8o5pcm'
114
+ '89qZFI87lcW3KY3TZI+u0HRsNne4xADY7xwMxgXAKTIaAHWaMbdXbWwxKtpmtTgnDoQt5mjQvBkYZIgf'
115
+ '1UWvuRy9hq6HoNE5lC2EXF0cNldYKIsutUe1iOdl5nnt5nmRAq+c6ITtUxbfD9xa9GX2ByHIpyzWmrKD'
116
+ 'q+Th6W3RiWqOTlQO3fLEi2sz3jcDMbmixTl8mtCV2SvgqnfMyrWlweeYkIbcBY5rOuGyPzhtjtK3QrZh'
117
+ '/nVKziQPr3j//sA7S9/WkDKY6PGriM7J3gdBcUrXIQ5y0De6f7zInjPgDVo0qjeKvDBpCyFjzFR5e+gL'
118
+ 'GLrlotP85BPPT2UU/BgeaLsx27coPKOTiPl/dlxeXsv/4hjfXZQhHeOWWDC2FHzLFXXvrkn31kXd20oX'
119
+ 't+zfNYW/32L+fl3/yq+yR0s0YgLIZ6kyMyKxezbE+fWBk6Rxb2lQlTk/Ek1q1w5O9pYs88XJuX5zkkyD'
120
+ '5viladeJYayfDONuHzsQuQoGTKPG8M4iMh+dZDI2Vlnj4nVBdny8/u/41/2b/Hddm/9D+mT+W/5n/L/F'
121
+ '8++O0yLMf/dHiJ91rEUD3jXUWu10o6IjP9BS0mafW9LeapkzVS4qwqfbSxTU1daoIjyki1Lp8kVevGpx'
122
+ 'stNYm0IFtPcDq2lud0XQ+6qlbaMuJMbxeDSOy/XyPx8omRJVYCqqwH9kRPEmVV2irHlDJnADxPhTW5wg'
123
+ '5plYzOknKuZP5NzBDgQn4MSL36la8M4AVXwKJNqmUsG64azfztxoY8fu4d6vxqpAQcKcJyvyrr9Fw+Qw'
124
+ 'RG6bVosXhQVp1nvbnKoc8y2g+aWGjIdnQ3rCuPy32WHAMAcR9rFqUZk3sukCs1Oq7D+rxtEen+dAj7AE'
125
+ '4Adb4OvrIb9smfLK3kqzr1v1uqpG0xl6djS9xSTRu85rxs9OJfjy7RktzsBRmdFHPELkFLqiK9RWRdQ/'
126
+ 'EWb/2IyVrJD0+UujSY8oayp1NTBPW+ZsgoRVF6jabSdJV1dpsKNVbrS3OffvzgSqvA4obgCeZIIOzOR5'
127
+ 'tSSs6dFYEJZAfwbMiwlGv2uW7DZlZFzRo6ywendlKfEtvQRwPJpmY8V5ambFRdeVKehpBt//45M6M5CR'
128
+ 'wkecRxmcpcR1gwrCxXRrF7UK5mKAkYcs/du57AqL9/tamL0V2lZGW9GDI6MPh45BsYqNX1s7YvHciXJW'
129
+ 'WI8po/G8Txm8D9clNtz/7gc1SpuCvJoK0WvvsAK9zjRZqgYOAnBgfSmNU9ETU2EQ6AYfhMNTGfLyUl1O'
130
+ 't4xRlIoFDXWL7ufaYaLUm6EsSYv6rjoup8jo+p4r4wsbvK6qAJu7ajCwRtGqwH7etKmxZvGm2lr34pot'
131
+ '9Q1uT+1GT2V9PUI3tS5z+tK52f9JHuqzrpWHaflfmYcnrp2HVEIesm+AwXVzWjeKGeAMTubms2JOecnp'
132
+ '6TlsIWCUbuYNt2i6npIPBYiKt96GHrUbIHstj4WnK0yB4CcsTMMpuLX3/KiZ+QSm2QwXPax7qX12mfsR'
133
+ 'GEKgyKIpSd0w6DX94aRcTL5snHw7QDp11xnF5Aurdouy0BUae5HQextK6Zv7GIuKr32FHPRpcQ46+Rzc'
134
+ 'zOyNi/Ncfq6e/wr9Ds7ChQwvxpu4QAjdMpl/sybzb5QxrzTIRYHb+aC5wpno2ENRx/p0rdFqxNdrPnPd'
135
+ '7dGczY3mLEO5xIX6PLPwdvDBzCldRjLl0bTp4GYWurClp5q7STtdZe+cKW8nopretjBB0xlJ7kJu8XGX'
136
+ 'Ohl3A3Jc98OWz/HNdffc7HDUr7xt9QqUpVim9T0c7lV8206UGJBpIGiGsPcpM9q8w6QFpq9KA17eLpsK'
137
+ 'bD6ElERpKZQCWAgawqwHP2t++n+oIf95reK6dq1CJtcq8rRYrSLc76lr3K//g/SUqeIaPzBTmamJK9IN'
138
+ 'YoG3yqz0AA0VxEUYF3jHXIzOOHVeycruV1mQtHcgMFCo+LXsI1UpCbXYv3s//b9xv18l3M/8L2uZr86F'
139
+ '/wpNbgIiM7dpIjcFnGKp/Ss3Ls9jpXZE3BAOWsVl6f0C5RNQ+Fj3lqKAIFI+lTJTrKPNZlNV8LnsaCIN'
140
+ 'odtPEqtufqSEFWv8RgYm6UEgcG+afMb+Sgvlzf44lL5IqSEF7X9AcSMLMTkDr7mpw7G4/E/HufV/Os7f'
141
+ '/a/GefArx7ns3xunnB8n1JywSmpBPGacJGRf41/j/9f4lBiO18FdepCf7TiPerG2D5dBiN/bRSm/jtn/'
142
+ 'EK+DBb8AcBOtmdsqf3X6elTIKd+b3hUs5VJ/ljHC3slp/pKRnfMAl/H+jKovHJz21Zn7v2jidL+cNf7B'
143
+ 'Ixxzapa5uJ27/qK2vfh57oaDmXtO/pBb+NfM8bK9HLtvdnb451zBy1mD4Te4on1Z4743uVvfylKWHOCs'
144
+ 'h7Ky5b/mbB9nlQ78mltxMquq9S1u1YWs9pLfcLf9NWuPfJC7o003ODDI3blTN976Lnf3izrlikPcmld0'
145
+ '2SmHuXte15W+fZi7t19XtX2Iu++3uvZn3uPu/4Nuz71HuAf+qBuc8T730J914x+9zzl8euWzI5zr+/rs'
146
+ 'b3zKlf9AL5Y6qBIK6UdhYZxGdo7fJGr5D1KEZ56rxZpjvWiL/26A/+NThOOeFP6LMOhX8HcZEq5BceeR'
147
+ 'aI9/LqQIzzixPa6h+O/Rw8btLyliLY+E81E8BTpLh+NFSDiPcSXg0xTCs8E8JMwjxtsBn6UQ3vjjZ6Lq'
148
+ 'uH6uB3y6OJZpcXi+aP8tif3tgOMHvzVIuH/0vusVgl0zEs5H8Y0KgXe7ZFweEd8Zh2P7R0X8BQneLuIv'
149
+ 'S/p5WsR7JfYvivgbEvu9Ij4gse8T8SMS+9+I4x2RjPc9wKfC8Wkk+Clqf0K0/1Jif17sX0Yk9v9nhTB/'
150
+ 'KiI2v9iepIR+ZhGJ/UylBLv5kn50Ir5Ygl8v4mYicbwmSui3mIjFD7a/lRLm8S4icR7vEvk8GMcH2z9I'
151
+ 'Cc8hqgkhvqP25SJeG4fjOHxY5LNFwnMLJfjxe0Qs3nA/28X7PiXxw9OUELc/IGJxi/GXKWE8PyMS82Uf'
152
+ 'JawR+wnhCzM8Dvv5N0X7oMT+HRE/LMF/K/L/WOLPEyIekYzrrIifk9hfEfu/Iukfk+OPJfZpSsF+iizR'
153
+ 'fpZS8FuGLNFv14v28yT2uUrBb4tliX5bqRT8bJEl+nmdUpi/O2XCfEbxb4r4OpmgN1HcqRSO75fF9Afj'
154
+ 'lSL+kAR/WCnczyWL07GFCG1VCnu7GsBnxOFPKgXeLTIh//hxMQj9CPBZcPy0TLguir8u4nsl+HtKYe/z'
155
+ 'G8Az4/DPRPsRif0/xPtekNxXM0X0owSfK+K4fo7Hl4q4UYKvFHGTBF8v4jYJ/rCIr5Pgj4h4pQR/SsQb'
156
+ 'JXi3iPsl+D4R75LgA1OENWovKfgpih8X8aAEvyLin0hwVaroT0n/BhH/pwRnRVwjT8SLRdwowdeJuEmC'
157
+ 'bxBxmwRvEvF1EvxxEa+U4C+kCnnUKI9bNwF/VcTbJXi/iD8vwT8S8Z9K8HERf0uC/03EhyU4nSYcn5Tw'
158
+ 'ZNIE+8sS+1wRT0lJxFeK+CwJfr+I3yDBN4l4gQT/nojfKcF3irhDgv84TYiPupRY3uF8P5Am5L8/RXie'
159
+ 'G8U/SIt+8TG2vuBA+1TEFRJ8NE3QU15Do/2AT/6YJugSvgcZZ49/HlIJeQ2138QSOF5c3+BZbOI/cx2O'
160
+ '+oaKSo/HDUdl1RurNzc4NlduFVsbPJWVDsfGGnezo3xTpcuDjydP1dY4oBF/uAVay5fGI9CpeH19ZQOc'
161
+ 'jzuI3c9VURGHCy3AxLP1W8qiZ7eUiVjNlk0iBi0Rq6huFLEG3KyL0thUW+uJO7kh/mRNbfTO1ZurG+Iv'
162
+ 'j/lio9gqr3FHXVHjFjG3B38K6MaEMTXU4gP43VS5uca1aVNtefSS2q3xt4yNuKEefJnAoc5hqmxyb4nz'
163
+ 'Q9lmxwZX9aYtMUrRpmtzdCTQioK1UedX13qiWNMk2BQD66vi/Jl41ypPguP4k9Fea9y1ngbCscG9paEe'
164
+ 'f5RXNlU34AP+Ib2rrH5xda6Jb9dU1pS7ty12s/i3ejJGINIWl9duqlicI4mqf4WakkPuGuY4uBNQiKiv'
165
+ 'AEwxDydaTAJJFrlSYGksMhP7mARMsThNtJgEkixypTEsGWcibLo2nBuLdQmzWsn4J4HcyenZmHjJJGCK'
166
+ 'RXOixSSQZJG7JcnNSYgpCUm+amlcyEv6mURMsQyQmDQlIRD7X4WYkpDcuLxIusqTdJWI5Aovrao3VDZU'
167
+ '11SC7ro8DZAIiWglkHezJtPinMWsy1OzfOkiF/4C26IaV3ltfZNpOf7i2pJ76ys99UtqXNWbl9i34W+n'
168
+ '1dg9tQ9XljfUL7lvxX1L6mu3eMorl0CqNVQuARabt9QsLnfEki3aFHQ9TtgFRJJuCcdCoiVAvLgnqnuC'
169
+ 'vEeNeX2PE/hJhXfE5tYR0/goyot8TJXiZT5BJJOFPkGw4qU+XuvjxT7moo3RJi/3k3ofRUXBT1D86DlB'
170
+ '8h2C5jsE0XfEssCRJPuJup8k/I545Y9KvyNO+x0J4j+p/o54+Z/Uf0fCAjC5AjgSloDENcCRsAhcYxWI'
171
+ 'XwaEVYD/LHfgdcDBH8evBI5rLgVx4SlmlDQO/yVsukaUXuuC2HoQF5ZfhZjiIlNiE9OqJCQ3CVkaF8uS'
172
+ 'fmLrQlxkS2xi0p6E5CaFvXTQksXhK/DcuPyQMqyVeiO2QMQljOSq2BIRF/sSm9gikYTkOpKXiWTIlAxd'
173
+ '48KljuSlIhkyOZIWC0fyauFIXi6SIVMylOtIXjGSIVMylOu49qLhuNaqsdohlPTiXyjqo1X9ahz4eA/w'
174
+ '3wNrmpc='
175
+ )
176
+
177
+ def load_bignum_bc():
178
+ data = zlib.decompress(base64.b64decode(_B64))
179
+ return binding.parse_bitcode(data)
@@ -1352,6 +1352,9 @@ def _parse_standard_statement(tokens: list[Token], pos: int):
1352
1352
  elif tok.type == TokenType.KEYWORD and tok.value == "dataclass":
1353
1353
  # `dataclass class X:` — auto-synthesized `__init__`/`__eq__`/`__str__`.
1354
1354
  node, pos = parse_dataclass_class(tokens, pos)
1355
+ elif tok.type == TokenType.KEYWORD and tok.value in ("interface", "protocol"):
1356
+ # `interface I:` or `protocol I:` (minimal)
1357
+ node, pos = parse_protocol_class(tokens, pos)
1355
1358
  elif tok.type == TokenType.KEYWORD and tok.value == "class":
1356
1359
  node, pos = parse_class(tokens, pos)
1357
1360
  elif tok.type == TokenType.KEYWORD and tok.value == "struct":
@@ -1687,6 +1690,56 @@ def parse_dataclass_class(tokens: list[Token], pos: int):
1687
1690
  return parse_class(tokens, pos, sealed=sealed, dataclass=True)
1688
1691
 
1689
1692
 
1693
+
1694
+ def parse_protocol_class(tokens: list[Token], pos: int):
1695
+ """Parse `interface I:` or `protocol I:` as a protocol definition."""
1696
+ tok = tokens[pos]
1697
+ pos += 1
1698
+ if pos >= len(tokens) or tokens[pos].type != TokenType.IDENTIFIER:
1699
+ raise ParseError(
1700
+ "Expected interface/protocol name", tokens[pos] if pos < len(tokens) else None
1701
+ )
1702
+ name = tokens[pos].value
1703
+ assert name is not None
1704
+ pos += 1
1705
+ generic_params, pos = parse_generic_params(tokens, pos)
1706
+ base = None
1707
+ if pos < len(tokens) and tokens[pos].type == TokenType.LPAREN:
1708
+ pos += 1
1709
+ if pos >= len(tokens) or tokens[pos].type != TokenType.IDENTIFIER:
1710
+ raise ParseError(
1711
+ "Expected base protocol name", tokens[pos] if pos < len(tokens) else None
1712
+ )
1713
+ base = tokens[pos].value
1714
+ pos += 1
1715
+ if pos >= len(tokens) or tokens[pos].type != TokenType.RPAREN:
1716
+ raise ParseError(
1717
+ 'Expected ")" after base protocol name',
1718
+ tokens[pos] if pos < len(tokens) else None,
1719
+ )
1720
+ pos += 1
1721
+ body, pos = parse_class_suite(tokens, pos)
1722
+ fields = []
1723
+ methods = []
1724
+ properties = []
1725
+ for stmt in body:
1726
+ if isinstance(stmt, FuncDef):
1727
+ methods.append(stmt)
1728
+ elif isinstance(stmt, VarDecl):
1729
+ fields.append(Field(stmt.name, stmt.var_type, token=stmt._token))
1730
+ elif isinstance(stmt, PropertyDef):
1731
+ properties.append(stmt)
1732
+ return ProtocolDef(
1733
+ name,
1734
+ base=base,
1735
+ fields=fields,
1736
+ methods=methods,
1737
+ properties=properties,
1738
+ generic_params=generic_params,
1739
+ token=tok,
1740
+ ), pos
1741
+
1742
+
1690
1743
  def parse_property(tokens: list[Token], pos: int):
1691
1744
  """Parse a `property name:` block with `get`/`set` accessor bodies."""
1692
1745
  tok = tokens[pos]
@@ -1988,12 +2041,13 @@ def parse_import(tokens: list[Token], pos: int):
1988
2041
 
1989
2042
 
1990
2043
  class Assign(Node):
1991
- __slots__ = ("_token", "dynamic", "target", "value")
2044
+ __slots__ = ("_token", "compound_op", "dynamic", "target", "value")
1992
2045
 
1993
- def __init__(self, target, value, token=None):
2046
+ def __init__(self, target, value, token=None, compound_op=None):
1994
2047
  self.target = target
1995
2048
  self.value = value
1996
2049
  self._token = token
2050
+ self.compound_op = compound_op
1997
2051
 
1998
2052
  def __repr__(self):
1999
2053
  return f"Assign({self.target}, {self.value})"
@@ -2303,10 +2357,15 @@ class AddrOf(Node):
2303
2357
 
2304
2358
 
2305
2359
  class SizeOf(Node):
2306
- __slots__ = ("_token", "type_expr")
2360
+ __slots__ = ("_token", "type_expr", "resolved_type")
2307
2361
 
2308
2362
  def __init__(self, type_expr, token=None):
2309
2363
  self.type_expr = type_expr
2364
+ # Semantic analysis fills this in: `sizeof(x)` where `x` names a
2365
+ # declared value resolves to the type OF that value (C semantics),
2366
+ # while `sizeof(T)` keeps the type name as written. Codegen sizes the
2367
+ # resolved type; the formatter prints `type_expr` unchanged.
2368
+ self.resolved_type = None
2310
2369
  self._token = token
2311
2370
 
2312
2371
  def __repr__(self):
@@ -2486,6 +2545,7 @@ class ClassDef(Node):
2486
2545
  "name",
2487
2546
  "properties",
2488
2547
  "sealed",
2548
+ "is_protocol",
2489
2549
  )
2490
2550
 
2491
2551
  def __init__(
@@ -2498,6 +2558,7 @@ class ClassDef(Node):
2498
2558
  sealed: bool = False,
2499
2559
  dataclass: bool = False,
2500
2560
  properties: list | None = None,
2561
+ is_protocol: bool = False,
2501
2562
  token=None,
2502
2563
  ):
2503
2564
  self.name = name
@@ -2508,6 +2569,7 @@ class ClassDef(Node):
2508
2569
  self.sealed = sealed
2509
2570
  self.dataclass = dataclass
2510
2571
  self.properties = properties or []
2572
+ self.is_protocol = is_protocol
2511
2573
  self.module = None
2512
2574
  self._token = token
2513
2575
 
@@ -2517,6 +2579,38 @@ class ClassDef(Node):
2517
2579
  return f"ClassDef({seal}{dc}{self.name}, base={self.base}, fields={self.fields}, properties={self.properties}, methods={self.methods})"
2518
2580
 
2519
2581
 
2582
+
2583
+ class ProtocolDef(Node):
2584
+ __slots__ = ("_token", "base", "name", "methods", "properties", "fields", "generic_params", "sealed", "is_protocol")
2585
+
2586
+ def __init__(
2587
+ self,
2588
+ name: str,
2589
+ base: str | None = None,
2590
+ methods: list | None = None,
2591
+ fields: list | None = None,
2592
+ properties: list | None = None,
2593
+ generic_params: list | None = None,
2594
+ token=None,
2595
+ ):
2596
+ self.name = name
2597
+ self.base = base
2598
+ self.methods = methods or []
2599
+ self.fields = fields or []
2600
+ self.properties = properties or []
2601
+ self.generic_params = generic_params or []
2602
+ self.sealed = False
2603
+ self.is_protocol = True
2604
+ self._token = token
2605
+
2606
+ def __repr__(self):
2607
+ return f"ProtocolDef({self.name}, base={self.base}, methods={self.methods})"
2608
+
2609
+
2610
+ # Alias
2611
+ InterfaceDef = ProtocolDef
2612
+
2613
+
2520
2614
  class PropertyDef(Node):
2521
2615
  """A `property name:` block holding paired `get`/`set` accessor bodies."""
2522
2616
 
@@ -3517,6 +3611,9 @@ def parse_expr_stmt(tokens: list[Token], pos: int):
3517
3611
  token=tok,
3518
3612
  ),
3519
3613
  token=tok,
3614
+ compound_op=(
3615
+ binop_op if not isinstance(target, Variable) else None
3616
+ ),
3520
3617
  ), pos
3521
3618
 
3522
3619
  _expect_newline(tokens, pos, tok)