cpyte 4.2.7__tar.gz → 4.3.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 (41) hide show
  1. {cpyte-4.2.7/source/cpyte.egg-info → cpyte-4.3.0}/PKG-INFO +1 -1
  2. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/__init__.py +1 -1
  3. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/astparse.py +262 -23
  4. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/bytecoding.py +272 -2
  5. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/formatter.py +19 -1
  6. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/lexar.py +2 -0
  7. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/semantic_analasis.py +474 -16
  8. {cpyte-4.2.7 → cpyte-4.3.0/source/cpyte.egg-info}/PKG-INFO +1 -1
  9. {cpyte-4.2.7 → cpyte-4.3.0}/MANIFEST.in +0 -0
  10. {cpyte-4.2.7 → cpyte-4.3.0}/pyproject.toml +0 -0
  11. {cpyte-4.2.7 → cpyte-4.3.0}/readme.md +0 -0
  12. {cpyte-4.2.7 → cpyte-4.3.0}/setup.cfg +0 -0
  13. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/__main__.py +0 -0
  14. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/_bignum_bc.py +0 -0
  15. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/_runtime_bc.py +0 -0
  16. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/bignum.c +0 -0
  17. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/clib.py +0 -0
  18. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/compiling.py +0 -0
  19. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/extension_hooks.py +0 -0
  20. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/gc_runtime.c +0 -0
  21. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/generate_bc.py +0 -0
  22. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/linker.py +0 -0
  23. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/lsp_server.py +0 -0
  24. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/mainpie.py +0 -0
  25. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/optimizations.py +0 -0
  26. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/package_manifest.py +0 -0
  27. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/runtime.c +0 -0
  28. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/runtime_scorpion.c +0 -0
  29. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/sef.py +0 -0
  30. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/ugc.h +0 -0
  31. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/ui.py +0 -0
  32. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/update_check.py +0 -0
  33. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/winjit_patch.py +0 -0
  34. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte/winjit_stubs.c +0 -0
  35. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte.egg-info/SOURCES.txt +0 -0
  36. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte.egg-info/dependency_links.txt +0 -0
  37. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte.egg-info/entry_points.txt +0 -0
  38. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte.egg-info/requires.txt +0 -0
  39. {cpyte-4.2.7 → cpyte-4.3.0}/source/cpyte.egg-info/top_level.txt +0 -0
  40. {cpyte-4.2.7 → cpyte-4.3.0}/test/test_bignum_jit.py +0 -0
  41. {cpyte-4.2.7 → cpyte-4.3.0}/test/test_fuzz_del_has.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cpyte
3
- Version: 4.2.7
3
+ Version: 4.3.0
4
4
  Summary: The Cpyte programming language compiler
5
5
  Author: Hoang Duy Tung
6
6
  License: MIT
@@ -1,4 +1,4 @@
1
- __version__ = "4.2.7"
1
+ __version__ = "4.3.0"
2
2
 
3
3
  # ---------------------------------------------------------------------------
4
4
  # Public library API.
@@ -187,7 +187,14 @@ class Index(Node):
187
187
 
188
188
  class Attr(Node):
189
189
  inferred_type: str | None
190
- __slots__ = ("_enum_member_value", "_token", "inferred_type", "name", "obj")
190
+ __slots__ = (
191
+ "_enum_member_value",
192
+ "_token",
193
+ "inferred_type",
194
+ "meta",
195
+ "name",
196
+ "obj",
197
+ )
191
198
 
192
199
  def __init__(self, obj, name: str, token=None):
193
200
  self.obj = obj
@@ -195,6 +202,7 @@ class Attr(Node):
195
202
  self._token = token
196
203
  self._enum_member_value = None
197
204
  self.inferred_type = None
205
+ self.meta = None
198
206
 
199
207
  def __repr__(self):
200
208
  return f"Attr({self.obj}, {self.name})"
@@ -828,13 +836,27 @@ def _parse_call_args(tokens: list[Token], pos: int, callee):
828
836
 
829
837
 
830
838
  def _parse_postfix(tokens: list[Token], pos: int, node):
831
- while pos < len(tokens) and tokens[pos].type in (
832
- TokenType.LPAREN,
833
- TokenType.LBRACKET,
834
- TokenType.DOT,
839
+ while pos < len(tokens) and (
840
+ tokens[pos].type in (
841
+ TokenType.LPAREN,
842
+ TokenType.LBRACKET,
843
+ TokenType.DOT,
844
+ )
845
+ or (tokens[pos].type == TokenType.KEYWORD and tokens[pos].value == "as")
835
846
  ):
836
847
  tok = tokens[pos]
837
- if tok.type == TokenType.LPAREN:
848
+ if tok.type == TokenType.KEYWORD and tok.value == "as":
849
+ pos += 1
850
+ if pos >= len(tokens) or tokens[pos].type != TokenType.IDENTIFIER:
851
+ raise ParseError(
852
+ "Expected a class name after 'as'",
853
+ tokens[pos] if pos < len(tokens) else None,
854
+ )
855
+ name = tokens[pos].value
856
+ assert name is not None
857
+ pos += 1
858
+ node = AsExpr(name, node, token=tok)
859
+ elif tok.type == TokenType.LPAREN:
838
860
  node, pos = _parse_call_args(tokens, pos, node)
839
861
  elif tok.type == TokenType.LBRACKET:
840
862
  pos += 1
@@ -1039,13 +1061,27 @@ def _parse_expr_iterative(tokens: list[Token], pos: int, min_prec: int):
1039
1061
  elif kind == "postfix":
1040
1062
  prefixes = frame[1]
1041
1063
  node = vals.pop()
1042
- while pos < len(tokens) and tokens[pos].type in (
1043
- TokenType.LPAREN,
1044
- TokenType.LBRACKET,
1045
- TokenType.DOT,
1064
+ while pos < len(tokens) and (
1065
+ tokens[pos].type in (
1066
+ TokenType.LPAREN,
1067
+ TokenType.LBRACKET,
1068
+ TokenType.DOT,
1069
+ )
1070
+ or (tokens[pos].type == TokenType.KEYWORD and tokens[pos].value == "as")
1046
1071
  ):
1047
1072
  ptok = tokens[pos]
1048
- if ptok.type == TokenType.LPAREN:
1073
+ if ptok.type == TokenType.KEYWORD and ptok.value == "as":
1074
+ pos += 1
1075
+ if pos >= len(tokens) or tokens[pos].type != TokenType.IDENTIFIER:
1076
+ raise ParseError(
1077
+ "Expected a class name after 'as'",
1078
+ tokens[pos] if pos < len(tokens) else None,
1079
+ )
1080
+ name = tokens[pos].value
1081
+ assert name is not None
1082
+ pos += 1
1083
+ node = AsExpr(name, node, token=ptok)
1084
+ elif ptok.type == TokenType.LPAREN:
1049
1085
  pos += 1
1050
1086
  frames.append(("call_done", prefixes))
1051
1087
  frames.append(("callargs", node, [], ptok))
@@ -1210,14 +1246,10 @@ def _parse_standard_statement(tokens: list[Token], pos: int):
1210
1246
  node, pos = parse_decorated_def(tokens, pos)
1211
1247
  elif tok.type == TokenType.KEYWORD and tok.value == "sealed":
1212
1248
  # `sealed class X:` — a closed, monomorphic class (no vtable).
1213
- pos += 1
1214
- if pos >= len(tokens) or (
1215
- tokens[pos].type != TokenType.KEYWORD or tokens[pos].value != "class"
1216
- ):
1217
- raise ParseError(
1218
- 'Expected "class" after "sealed"', tokens[pos] if pos < len(tokens) else None
1219
- )
1220
- node, pos = parse_class(tokens, pos, sealed=True)
1249
+ node, pos = parse_sealed_class(tokens, pos)
1250
+ elif tok.type == TokenType.KEYWORD and tok.value == "dataclass":
1251
+ # `dataclass class X:` — auto-synthesized `__init__`/`__eq__`/`__str__`.
1252
+ node, pos = parse_dataclass_class(tokens, pos)
1221
1253
  elif tok.type == TokenType.KEYWORD and tok.value == "class":
1222
1254
  node, pos = parse_class(tokens, pos)
1223
1255
  elif tok.type == TokenType.KEYWORD and tok.value == "struct":
@@ -1383,7 +1415,7 @@ def parse_decorated_def(tokens: list[Token], pos: int):
1383
1415
  return _parse_func_with_visibility(tokens, pos, visibility, tok)
1384
1416
 
1385
1417
 
1386
- def parse_class(tokens: list[Token], pos: int, sealed: bool = False):
1418
+ def parse_class(tokens: list[Token], pos: int, sealed: bool = False, dataclass: bool = False):
1387
1419
  tok = tokens[pos]
1388
1420
  pos += 1
1389
1421
  if pos >= len(tokens) or tokens[pos].type != TokenType.IDENTIFIER:
@@ -1409,25 +1441,182 @@ def parse_class(tokens: list[Token], pos: int, sealed: bool = False):
1409
1441
  tokens[pos] if pos < len(tokens) else None,
1410
1442
  )
1411
1443
  pos += 1
1412
- body, pos = parse_suite(tokens, pos)
1444
+ body, pos = parse_class_suite(tokens, pos)
1413
1445
  fields = []
1414
1446
  methods = []
1447
+ properties = []
1415
1448
  for stmt in body:
1416
1449
  if isinstance(stmt, FuncDef):
1417
1450
  methods.append(stmt)
1418
1451
  elif isinstance(stmt, VarDecl):
1419
1452
  fields.append(Field(stmt.name, stmt.var_type, token=stmt._token))
1453
+ elif isinstance(stmt, PropertyDef):
1454
+ properties.append(stmt)
1420
1455
  return ClassDef(
1421
1456
  name,
1422
1457
  base=base,
1423
1458
  fields=fields,
1424
1459
  methods=methods,
1460
+ properties=properties,
1425
1461
  generic_params=generic_params,
1426
1462
  sealed=sealed,
1463
+ dataclass=dataclass,
1427
1464
  token=tok,
1428
1465
  ), pos
1429
1466
 
1430
1467
 
1468
+ def parse_class_suite(tokens: list[Token], pos: int):
1469
+ """Parse a class body suite, intercepting `property name:` blocks."""
1470
+ if pos >= len(tokens) or tokens[pos].type != TokenType.COLON:
1471
+ raise ParseError('Expected ":"', tokens[pos] if pos < len(tokens) else None)
1472
+ pos += 1
1473
+
1474
+ if pos >= len(tokens) or tokens[pos].type != TokenType.NEWLINE:
1475
+ raise ParseError(
1476
+ 'Expected newline after ":"', tokens[pos] if pos < len(tokens) else None
1477
+ )
1478
+ pos += 1
1479
+
1480
+ if pos >= len(tokens) or tokens[pos].type != TokenType.INDENT:
1481
+ raise ParseError(
1482
+ "Expected indented block", tokens[pos] if pos < len(tokens) else None
1483
+ )
1484
+ pos += 1
1485
+
1486
+ stmts = []
1487
+ while pos < len(tokens) and tokens[pos].type not in (
1488
+ TokenType.DEDENT,
1489
+ TokenType.EOF,
1490
+ ):
1491
+ if (
1492
+ tokens[pos].type == TokenType.IDENTIFIER
1493
+ and tokens[pos].value == "property"
1494
+ ):
1495
+ pnode, pos = parse_property(tokens, pos)
1496
+ stmts.append(pnode)
1497
+ while pos < len(tokens) and tokens[pos].type == TokenType.NEWLINE:
1498
+ pos += 1
1499
+ continue
1500
+ stmt, pos = parse_statement(tokens, pos)
1501
+ if stmt is not None:
1502
+ stmts.append(stmt)
1503
+ while pos < len(tokens) and tokens[pos].type == TokenType.NEWLINE:
1504
+ pos += 1
1505
+ if pos < len(tokens) and tokens[pos].type == TokenType.DEDENT:
1506
+ pos += 1
1507
+ return stmts, pos
1508
+
1509
+
1510
+ def parse_sealed_class(tokens: list[Token], pos: int):
1511
+ """Parse `sealed class X:` (or `sealed dataclass class X:`) — a closed,
1512
+ monomorphic class (no vtable)."""
1513
+ pos += 1
1514
+ dataclass = False
1515
+ if (
1516
+ pos < len(tokens)
1517
+ and tokens[pos].type == TokenType.KEYWORD
1518
+ and tokens[pos].value == "dataclass"
1519
+ ):
1520
+ dataclass = True
1521
+ pos += 1
1522
+ if pos >= len(tokens) or (
1523
+ tokens[pos].type != TokenType.KEYWORD or tokens[pos].value != "class"
1524
+ ):
1525
+ raise ParseError(
1526
+ 'Expected "class" after "sealed"',
1527
+ tokens[pos] if pos < len(tokens) else None,
1528
+ )
1529
+ return parse_class(tokens, pos, sealed=True, dataclass=dataclass)
1530
+
1531
+
1532
+ def parse_dataclass_class(tokens: list[Token], pos: int):
1533
+ """Parse `dataclass class X:` (or `sealed dataclass class X:`) — a class
1534
+ that auto-synthesizes `__init__`/`__eq__`/`__str__` from its fields
1535
+ (Python-style dataclass)."""
1536
+ pos += 1
1537
+ sealed = False
1538
+ if (
1539
+ pos < len(tokens)
1540
+ and tokens[pos].type == TokenType.KEYWORD
1541
+ and tokens[pos].value == "sealed"
1542
+ ):
1543
+ sealed = True
1544
+ pos += 1
1545
+ if pos >= len(tokens) or (
1546
+ tokens[pos].type != TokenType.KEYWORD or tokens[pos].value != "class"
1547
+ ):
1548
+ raise ParseError(
1549
+ 'Expected "class" after "dataclass"',
1550
+ tokens[pos] if pos < len(tokens) else None,
1551
+ )
1552
+ return parse_class(tokens, pos, sealed=sealed, dataclass=True)
1553
+
1554
+
1555
+ def parse_property(tokens: list[Token], pos: int):
1556
+ """Parse a `property name:` block with `get`/`set` accessor bodies."""
1557
+ tok = tokens[pos]
1558
+ pos += 1
1559
+ if pos >= len(tokens) or tokens[pos].type != TokenType.IDENTIFIER:
1560
+ raise ParseError(
1561
+ "Expected property name after `property`",
1562
+ tokens[pos] if pos < len(tokens) else None,
1563
+ )
1564
+ name = tokens[pos].value
1565
+ assert name is not None
1566
+ pos += 1
1567
+ if pos >= len(tokens) or tokens[pos].type != TokenType.COLON:
1568
+ raise ParseError(
1569
+ 'Expected ":" after property name',
1570
+ tokens[pos] if pos < len(tokens) else None,
1571
+ )
1572
+ pos += 1
1573
+ if pos >= len(tokens) or tokens[pos].type != TokenType.NEWLINE:
1574
+ raise ParseError(
1575
+ 'Expected newline after ":"', tokens[pos] if pos < len(tokens) else None
1576
+ )
1577
+ pos += 1
1578
+ if pos >= len(tokens) or tokens[pos].type != TokenType.INDENT:
1579
+ raise ParseError(
1580
+ "Expected indented block", tokens[pos] if pos < len(tokens) else None
1581
+ )
1582
+ pos += 1
1583
+
1584
+ get = None
1585
+ setm = None
1586
+ while pos < len(tokens) and tokens[pos].type not in (
1587
+ TokenType.DEDENT,
1588
+ TokenType.EOF,
1589
+ ):
1590
+ if (
1591
+ tokens[pos].type == TokenType.IDENTIFIER
1592
+ and tokens[pos].value in ("get", "set")
1593
+ and pos + 1 < len(tokens)
1594
+ and tokens[pos + 1].type == TokenType.COLON
1595
+ ):
1596
+ atok = tokens[pos]
1597
+ aname = tokens[pos].value
1598
+ abody, pos = parse_suite(tokens, pos + 1)
1599
+ accessor = FuncDef(aname, {}, abody, "auto", token=atok)
1600
+ if aname == "get":
1601
+ get = accessor
1602
+ else:
1603
+ setm = accessor
1604
+ else:
1605
+ stmt, pos = parse_statement(tokens, pos)
1606
+ if isinstance(stmt, FuncDef):
1607
+ if stmt.name == "get":
1608
+ get = stmt
1609
+ elif stmt.name == "set":
1610
+ setm = stmt
1611
+ while pos < len(tokens) and tokens[pos].type == TokenType.NEWLINE:
1612
+ pos += 1
1613
+ if pos < len(tokens) and tokens[pos].type == TokenType.DEDENT:
1614
+ pos += 1
1615
+ if get is None:
1616
+ raise ParseError("Expected a `get` accessor in property block", tok)
1617
+ return PropertyDef(name, get, setm, token=tok), pos
1618
+
1619
+
1431
1620
  def parse_try(tokens: list[Token], pos: int):
1432
1621
  tok = tokens[pos]
1433
1622
  pos += 1
@@ -1706,6 +1895,7 @@ class FuncDef(Node):
1706
1895
  "const_params",
1707
1896
  "decorators",
1708
1897
  "generic_params",
1898
+ "meta",
1709
1899
  "name",
1710
1900
  "params",
1711
1901
  "rettype",
@@ -1732,6 +1922,7 @@ class FuncDef(Node):
1732
1922
  self.generic_params = generic_params or []
1733
1923
  self.const_params = const_params or []
1734
1924
  self.decorators = decorators or []
1925
+ self.meta = None
1735
1926
  self._token = token
1736
1927
 
1737
1928
  def __repr__(self):
@@ -1928,7 +2119,7 @@ class Raise(Node):
1928
2119
 
1929
2120
 
1930
2121
  class NewExpr(Node):
1931
- __slots__ = ("_token", "size", "type_expr", "args")
2122
+ __slots__ = ("_token", "size", "type_expr", "args", "inferred_type")
1932
2123
 
1933
2124
  def __init__(self, type_expr, size=None, token=None, args=None):
1934
2125
  self.type_expr = type_expr
@@ -1993,6 +2184,27 @@ class CastExpr(Node):
1993
2184
  return f"CastExpr({self.type_expr}, {self.expr})"
1994
2185
 
1995
2186
 
2187
+ class AsExpr(Node):
2188
+ """`expr as T` — safe runtime downcast (C#/Kotlin style).
2189
+
2190
+ `x as T` returns `x` re-typed as `T*` when the runtime class of `x` is a
2191
+ descendant-or-equal of `T` (checked through the class-id RTTI ancestor
2192
+ grid), and `null` otherwise. Unlike a parenthesized `(T)x` hard cast, an
2193
+ `as` that fails yields null rather than silently re-typing the pointer.
2194
+ """
2195
+
2196
+ __slots__ = ("_token", "inferred_type", "type_expr", "expr", "meta")
2197
+
2198
+ def __init__(self, type_expr: str, expr, token=None):
2199
+ self.type_expr = type_expr
2200
+ self.expr = expr
2201
+ self._token = token
2202
+ self.inferred_type = None
2203
+
2204
+ def __repr__(self):
2205
+ return f"AsExpr({self.expr} as {self.type_expr})"
2206
+
2207
+
1996
2208
  class BorrowExpr(Node):
1997
2209
  """`borrow x` or `borrow mut x` — create a reference to x.
1998
2210
 
@@ -2123,10 +2335,12 @@ class ClassDef(Node):
2123
2335
  __slots__ = (
2124
2336
  "_token",
2125
2337
  "base",
2338
+ "dataclass",
2126
2339
  "fields",
2127
2340
  "generic_params",
2128
2341
  "methods",
2129
2342
  "name",
2343
+ "properties",
2130
2344
  "sealed",
2131
2345
  )
2132
2346
 
@@ -2138,6 +2352,8 @@ class ClassDef(Node):
2138
2352
  methods: list | None = None,
2139
2353
  generic_params: list | None = None,
2140
2354
  sealed: bool = False,
2355
+ dataclass: bool = False,
2356
+ properties: list | None = None,
2141
2357
  token=None,
2142
2358
  ):
2143
2359
  self.name = name
@@ -2146,11 +2362,30 @@ class ClassDef(Node):
2146
2362
  self.methods = methods or []
2147
2363
  self.generic_params = generic_params or []
2148
2364
  self.sealed = sealed
2365
+ self.dataclass = dataclass
2366
+ self.properties = properties or []
2149
2367
  self._token = token
2150
2368
 
2151
2369
  def __repr__(self):
2152
2370
  seal = "sealed " if self.sealed else ""
2153
- return f"ClassDef({seal}{self.name}, base={self.base}, fields={self.fields}, methods={self.methods})"
2371
+ dc = "dataclass " if self.dataclass else ""
2372
+ return f"ClassDef({seal}{dc}{self.name}, base={self.base}, fields={self.fields}, properties={self.properties}, methods={self.methods})"
2373
+
2374
+
2375
+ class PropertyDef(Node):
2376
+ """A `property name:` block holding paired `get`/`set` accessor bodies."""
2377
+
2378
+ __slots__ = ("_token", "name", "get", "set", "_ptype")
2379
+
2380
+ def __init__(self, name: str, get, set=None, token=None):
2381
+ self.name = name
2382
+ self.get = get
2383
+ self.set = set
2384
+ self._ptype = None
2385
+ self._token = token
2386
+
2387
+ def __repr__(self):
2388
+ return f"PropertyDef({self.name}, get={self.get and self.get.name}, set={self.set and self.set.name})"
2154
2389
 
2155
2390
 
2156
2391
  def parse_ccode(tokens: list[Token], pos: int):
@@ -2649,6 +2884,8 @@ def parse_statement(tokens: list[Token], pos: int):
2649
2884
  "import",
2650
2885
  "enum",
2651
2886
  "type",
2887
+ "sealed",
2888
+ "dataclass",
2652
2889
  ):
2653
2890
  handler = {
2654
2891
  "while": parse_while,
@@ -2658,6 +2895,8 @@ def parse_statement(tokens: list[Token], pos: int):
2658
2895
  "import": parse_import,
2659
2896
  "enum": parse_enum,
2660
2897
  "type": parse_type_alias,
2898
+ "sealed": parse_sealed_class,
2899
+ "dataclass": parse_dataclass_class,
2661
2900
  }[tok.value]
2662
2901
  return handler(tokens, pos)
2663
2902