cinderx 2026.1.16.2__cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.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 (68) hide show
  1. __static__/__init__.py +641 -0
  2. __static__/compiler_flags.py +8 -0
  3. __static__/enum.py +160 -0
  4. __static__/native_utils.py +77 -0
  5. __static__/type_code.py +48 -0
  6. __strict__/__init__.py +39 -0
  7. _cinderx.so +0 -0
  8. cinderx/__init__.py +577 -0
  9. cinderx/__pycache__/__init__.cpython-314.pyc +0 -0
  10. cinderx/_asyncio.py +156 -0
  11. cinderx/compileall.py +710 -0
  12. cinderx/compiler/__init__.py +40 -0
  13. cinderx/compiler/__main__.py +137 -0
  14. cinderx/compiler/config.py +7 -0
  15. cinderx/compiler/consts.py +72 -0
  16. cinderx/compiler/debug.py +70 -0
  17. cinderx/compiler/dis_stable.py +283 -0
  18. cinderx/compiler/errors.py +151 -0
  19. cinderx/compiler/flow_graph_optimizer.py +1287 -0
  20. cinderx/compiler/future.py +91 -0
  21. cinderx/compiler/misc.py +32 -0
  22. cinderx/compiler/opcode_cinder.py +18 -0
  23. cinderx/compiler/opcode_static.py +100 -0
  24. cinderx/compiler/opcodebase.py +158 -0
  25. cinderx/compiler/opcodes.py +991 -0
  26. cinderx/compiler/optimizer.py +547 -0
  27. cinderx/compiler/pyassem.py +3711 -0
  28. cinderx/compiler/pycodegen.py +7660 -0
  29. cinderx/compiler/pysourceloader.py +62 -0
  30. cinderx/compiler/static/__init__.py +1404 -0
  31. cinderx/compiler/static/compiler.py +629 -0
  32. cinderx/compiler/static/declaration_visitor.py +335 -0
  33. cinderx/compiler/static/definite_assignment_checker.py +280 -0
  34. cinderx/compiler/static/effects.py +160 -0
  35. cinderx/compiler/static/module_table.py +666 -0
  36. cinderx/compiler/static/type_binder.py +2176 -0
  37. cinderx/compiler/static/types.py +10580 -0
  38. cinderx/compiler/static/util.py +81 -0
  39. cinderx/compiler/static/visitor.py +91 -0
  40. cinderx/compiler/strict/__init__.py +69 -0
  41. cinderx/compiler/strict/class_conflict_checker.py +249 -0
  42. cinderx/compiler/strict/code_gen_base.py +409 -0
  43. cinderx/compiler/strict/common.py +507 -0
  44. cinderx/compiler/strict/compiler.py +352 -0
  45. cinderx/compiler/strict/feature_extractor.py +130 -0
  46. cinderx/compiler/strict/flag_extractor.py +97 -0
  47. cinderx/compiler/strict/loader.py +827 -0
  48. cinderx/compiler/strict/preprocessor.py +11 -0
  49. cinderx/compiler/strict/rewriter/__init__.py +5 -0
  50. cinderx/compiler/strict/rewriter/remove_annotations.py +84 -0
  51. cinderx/compiler/strict/rewriter/rewriter.py +975 -0
  52. cinderx/compiler/strict/runtime.py +77 -0
  53. cinderx/compiler/symbols.py +1754 -0
  54. cinderx/compiler/unparse.py +414 -0
  55. cinderx/compiler/visitor.py +194 -0
  56. cinderx/jit.py +230 -0
  57. cinderx/opcode.py +202 -0
  58. cinderx/static.py +113 -0
  59. cinderx/strictmodule.py +6 -0
  60. cinderx/test_support.py +341 -0
  61. cinderx-2026.1.16.2.dist-info/METADATA +15 -0
  62. cinderx-2026.1.16.2.dist-info/RECORD +68 -0
  63. cinderx-2026.1.16.2.dist-info/WHEEL +6 -0
  64. cinderx-2026.1.16.2.dist-info/licenses/LICENSE +21 -0
  65. cinderx-2026.1.16.2.dist-info/top_level.txt +5 -0
  66. opcodes/__init__.py +0 -0
  67. opcodes/assign_opcode_numbers.py +272 -0
  68. opcodes/cinderx_opcodes.py +121 -0
@@ -0,0 +1,91 @@
1
+ # Portions copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # pyre-strict
3
+
4
+ """Parser for future statements"""
5
+
6
+ import ast
7
+
8
+ from .visitor import ASTVisitor
9
+
10
+
11
+ class FutureParser(ASTVisitor):
12
+ features = (
13
+ "nested_scopes",
14
+ "generators",
15
+ "division",
16
+ "absolute_import",
17
+ "with_statement",
18
+ "print_function",
19
+ "unicode_literals",
20
+ "generator_stop",
21
+ "barry_as_FLUFL",
22
+ "annotations",
23
+ )
24
+
25
+ def __init__(self) -> None:
26
+ super().__init__()
27
+ self.valid: set[ast.ImportFrom] = set()
28
+ self.found_features: set[str] = set()
29
+ self.possible_docstring = True
30
+
31
+ def visitModule(self, node: ast.Module) -> None:
32
+ for s in node.body:
33
+ if (
34
+ self.possible_docstring
35
+ and isinstance(s, ast.Expr)
36
+ and isinstance(s.value, ast.Constant)
37
+ and isinstance(s.value.value, str)
38
+ ):
39
+ self.possible_docstring = False
40
+ continue
41
+ # no docstring after first statement
42
+ self.possible_docstring = False
43
+ if not self.check_stmt(s):
44
+ break
45
+
46
+ def check_stmt(self, stmt: ast.stmt) -> bool:
47
+ if isinstance(stmt, ast.ImportFrom) and stmt.module == "__future__":
48
+ for alias in stmt.names:
49
+ name = alias.name
50
+ if name in self.features:
51
+ self.found_features.add(name)
52
+ elif name == "braces":
53
+ raise SyntaxError("not a chance")
54
+ else:
55
+ raise SyntaxError("future feature %s is not defined" % name)
56
+ self.valid.add(stmt)
57
+ return True
58
+ return False
59
+
60
+ def get_features(self) -> set[str]:
61
+ """Return set of features enabled by future statements"""
62
+ return self.found_features
63
+
64
+ def get_valid(self) -> set[ast.ImportFrom]:
65
+ """Return set of valid future statements"""
66
+ return self.valid
67
+
68
+
69
+ class BadFutureParser(ASTVisitor):
70
+ """Check for invalid future statements"""
71
+
72
+ def __init__(self, valid_parser: FutureParser) -> None:
73
+ super().__init__()
74
+ self.valid_parser = valid_parser
75
+
76
+ def visitImportFrom(self, node: ast.ImportFrom) -> None:
77
+ if node.module != "__future__":
78
+ return
79
+ if node in self.valid_parser.get_valid():
80
+ return
81
+ raise SyntaxError(
82
+ "from __future__ imports must occur at the beginning of the file"
83
+ )
84
+
85
+
86
+ def find_futures(node: ast.AST) -> set[str]:
87
+ p1 = FutureParser()
88
+ p2 = BadFutureParser(p1)
89
+ p1.visit(node)
90
+ p2.visit(node)
91
+ return p1.get_features()
@@ -0,0 +1,32 @@
1
+ # Portions copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # pyre-strict
3
+
4
+
5
+ MANGLE_LEN = 256 # magic constant from compile.c
6
+
7
+
8
+ def mangle(name: str, klass: str | None) -> str:
9
+ if klass is None:
10
+ return name
11
+ if not name.startswith("__"):
12
+ return name
13
+ if len(name) + 2 >= MANGLE_LEN:
14
+ return name
15
+ # TODO: Probably need to split and mangle recursively?
16
+ if "." in name:
17
+ return name
18
+ if name.endswith("__"):
19
+ return name
20
+ try:
21
+ i = 0
22
+ while klass[i] == "_":
23
+ i = i + 1
24
+ except IndexError:
25
+ return name
26
+ klass = klass[i:]
27
+
28
+ tlen = len(klass) + len(name)
29
+ if tlen > MANGLE_LEN:
30
+ klass = klass[: MANGLE_LEN - tlen]
31
+
32
+ return "_{}{}".format(klass, name)
@@ -0,0 +1,18 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # pyre-strict
3
+
4
+ from .opcodebase import Opcode
5
+ from .opcodes import opcode as base_opcode
6
+
7
+
8
+ opcode: Opcode = base_opcode.copy()
9
+ opcode.def_op("LOAD_METHOD_SUPER", 198)
10
+ opcode.hasconst.add("LOAD_SUPER_METHOD")
11
+ opcode.def_op("LOAD_ATTR_SUPER", 199)
12
+ opcode.hasconst.add("LOAD_ATTR_SUPER")
13
+
14
+
15
+ opcode.stack_effects.update(
16
+ LOAD_METHOD_SUPER=-1,
17
+ LOAD_ATTR_SUPER=-2,
18
+ )
@@ -0,0 +1,100 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ # pyre-strict
4
+
5
+ from .opcode_cinder import opcode as opcode_cinder
6
+ from .opcodebase import Opcode
7
+
8
+ opcode: Opcode = opcode_cinder.copy()
9
+ opcode.def_op("INVOKE_METHOD", 158)
10
+ opcode.hasconst.add("INVOKE_METHOD")
11
+ opcode.def_op("LOAD_FIELD", 159)
12
+ opcode.hasconst.add("LOAD_FIELD")
13
+ opcode.def_op("STORE_FIELD", 166)
14
+ opcode.hasconst.add("STORE_FIELD")
15
+ opcode.def_op("BUILD_CHECKED_LIST", 168)
16
+ opcode.hasconst.add("BUILD_CHECKED_LIST")
17
+ opcode.def_op("LOAD_TYPE", 169)
18
+ opcode.hasconst.add("LOAD_TYPE")
19
+ opcode.def_op("CAST", 170)
20
+ opcode.hasconst.add("CAST")
21
+ opcode.def_op("LOAD_LOCAL", 171)
22
+ opcode.hasconst.add("LOAD_LOCAL")
23
+ opcode.def_op("STORE_LOCAL", 172)
24
+ opcode.hasconst.add("STORE_LOCAL")
25
+ opcode.def_op("PRIMITIVE_BOX", 174)
26
+ opcode.jabs_op("POP_JUMP_IF_ZERO", 175)
27
+ opcode.jabs_op("POP_JUMP_IF_NONZERO", 176)
28
+ opcode.def_op("PRIMITIVE_UNBOX", 177)
29
+ opcode.def_op("PRIMITIVE_BINARY_OP", 178)
30
+ opcode.def_op("PRIMITIVE_UNARY_OP", 179)
31
+ opcode.def_op("PRIMITIVE_COMPARE_OP", 180)
32
+ opcode.def_op("LOAD_ITERABLE_ARG", 181)
33
+ opcode.def_op("LOAD_MAPPING_ARG", 182)
34
+ opcode.def_op("INVOKE_FUNCTION", 183)
35
+ opcode.hasconst.add("INVOKE_FUNCTION")
36
+ opcode.jabs_op("JUMP_IF_ZERO_OR_POP", 184)
37
+ opcode.jabs_op("JUMP_IF_NONZERO_OR_POP", 185)
38
+ opcode.def_op("FAST_LEN", 186)
39
+ opcode.def_op("CONVERT_PRIMITIVE", 187)
40
+ opcode.def_op("INVOKE_NATIVE", 189)
41
+ opcode.hasconst.add("INVOKE_NATIVE")
42
+ opcode.def_op("LOAD_CLASS", 190)
43
+ opcode.hasconst.add("LOAD_CLASS")
44
+ opcode.def_op("BUILD_CHECKED_MAP", 191)
45
+ opcode.hasconst.add("BUILD_CHECKED_MAP")
46
+ opcode.def_op("SEQUENCE_GET", 192)
47
+ opcode.def_op("SEQUENCE_SET", 193)
48
+ opcode.def_op("LIST_DEL", 194)
49
+ opcode.def_op("REFINE_TYPE", 195)
50
+ opcode.hasconst.add("REFINE_TYPE")
51
+ opcode.def_op("PRIMITIVE_LOAD_CONST", 196)
52
+ opcode.hasconst.add("PRIMITIVE_LOAD_CONST")
53
+ opcode.def_op("RETURN_PRIMITIVE", 197)
54
+ opcode.def_op("TP_ALLOC", 200)
55
+ opcode.hasconst.add("TP_ALLOC")
56
+
57
+
58
+ def _load_mapping_arg_effect(oparg: int, _jmp: int = 0) -> int:
59
+ if oparg == 2:
60
+ return -1
61
+ elif oparg == 3:
62
+ return -2
63
+ return 1
64
+
65
+
66
+ opcode.stack_effects.update(
67
+ INVOKE_METHOD=lambda oparg, jmp: -(oparg[1] + 1),
68
+ LOAD_METHOD_STATIC=1,
69
+ LOAD_FIELD=0,
70
+ STORE_FIELD=-2,
71
+ CAST=0,
72
+ LOAD_LOCAL=1,
73
+ STORE_LOCAL=-1,
74
+ PRIMITIVE_BOX=0,
75
+ POP_JUMP_IF_ZERO=-1,
76
+ POP_JUMP_IF_NONZERO=-1,
77
+ PRIMITIVE_UNBOX=0,
78
+ PRIMITIVE_BINARY_OP=lambda oparg, jmp: -1,
79
+ PRIMITIVE_UNARY_OP=lambda oparg, jmp: 0,
80
+ PRIMITIVE_COMPARE_OP=lambda oparg, jmp: -1,
81
+ LOAD_ITERABLE_ARG=1,
82
+ LOAD_MAPPING_ARG=_load_mapping_arg_effect,
83
+ INVOKE_FUNCTION=lambda oparg, jmp=0: (-oparg[1]) + 1,
84
+ INVOKE_NATIVE=lambda oparg, jmp=0: (-len(oparg[1])) + 2,
85
+ JUMP_IF_ZERO_OR_POP=lambda oparg, jmp=0: 0 if jmp else -1,
86
+ JUMP_IF_NONZERO_OR_POP=lambda oparg, jmp=0: 0 if jmp else -1,
87
+ FAST_LEN=0,
88
+ CONVERT_PRIMITIVE=0,
89
+ LOAD_CLASS=1,
90
+ BUILD_CHECKED_MAP=lambda oparg, jmp: 1 - 2 * oparg[1],
91
+ SEQUENCE_GET=-1,
92
+ SEQUENCE_SET=-3,
93
+ LIST_DEL=-2,
94
+ REFINE_TYPE=0,
95
+ PRIMITIVE_LOAD_CONST=1,
96
+ RETURN_PRIMITIVE=-1,
97
+ TP_ALLOC=1,
98
+ BUILD_CHECKED_LIST=lambda oparg, jmp: 1 - oparg[1],
99
+ LOAD_TYPE=0,
100
+ )
@@ -0,0 +1,158 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # pyre-strict
3
+ from typing import Callable
4
+
5
+
6
+ class Opcode:
7
+ CMP_OP = (
8
+ "<",
9
+ "<=",
10
+ "==",
11
+ "!=",
12
+ ">",
13
+ ">=",
14
+ "BAD",
15
+ )
16
+ CONTAINS_OP_ARGS = (
17
+ "in",
18
+ "not in",
19
+ )
20
+ IS_OP_ARGS = (
21
+ "is",
22
+ "is not",
23
+ )
24
+
25
+ HAVE_ARGUMENT = 90 # Opcodes from here have an argument:
26
+ EXTENDED_ARG = 144
27
+ EXTENDED_OPCODE = 126
28
+ CODEUNIT_SIZE = 2
29
+
30
+ def __init__(self) -> None:
31
+ self.hasconst: set[str] = set()
32
+ self.hasname: set[int] = set()
33
+ self.hasjrel: set[int] = set()
34
+ self.hasjabs: set[int] = set()
35
+ self.haslocal: set[int] = set()
36
+ self.hascompare: set[int] = set()
37
+ self.hasfree: set[int] = set()
38
+ self.shadowop: set[int] = set()
39
+
40
+ self.opmap: dict[str, int] = {}
41
+ self.opname: list[str] = ["<{!r}>".format(op) for op in range(256)]
42
+ self.stack_effects: dict[str, object] = {}
43
+
44
+ # New for 3.14, we need to know popped vs pushed for the load borrow analysis.
45
+ self.popped: dict[str, int | Callable[[object], int]] = {}
46
+ self.pushed: dict[str, int | Callable[[object], int]] = {}
47
+
48
+ def stack_effect(self, opcode: int, oparg, jump: int) -> int: # pyre-ignore[2]
49
+ oparg_int = 0
50
+ if opcode >= self.HAVE_ARGUMENT:
51
+ if oparg is None:
52
+ raise ValueError(
53
+ "stack_effect: opcode requires oparg but oparg was not specified"
54
+ )
55
+ oparg_int = int(oparg)
56
+ elif oparg is not None:
57
+ raise ValueError(
58
+ "stack_effect: opcode does not permit oparg but oparg was specified"
59
+ )
60
+ # pyre-fixme[6]: For 1st argument expected `Optional[bool]` but got `int`.
61
+ jump_int = {None: -1, True: 1, False: 0}.get(jump)
62
+ if jump_int is None:
63
+ raise ValueError("stack_effect: jump must be False, True or None")
64
+ opname = self.opname[opcode]
65
+ return self.stack_effect_raw(opname, oparg_int, jump_int)
66
+
67
+ def stack_effect_raw(self, opname: str, oparg, jump: int) -> int: # pyre-ignore[2]
68
+ effect = self.stack_effects.get(opname)
69
+ if effect is None:
70
+ raise ValueError(
71
+ f"Error, opcode {opname} was not found, please update opcode.stack_effects"
72
+ )
73
+ if isinstance(effect, int):
74
+ return effect
75
+ else:
76
+ return effect(oparg, jump) # pyre-ignore[29]
77
+
78
+ def get_num_popped(self, opname: str, oparg: object) -> int:
79
+ popped = self.popped.get(opname)
80
+ if popped is None:
81
+ raise ValueError(
82
+ f"Error, opcode {opname} was not found, please update opcode.stack_effects"
83
+ )
84
+ if isinstance(popped, int):
85
+ return popped
86
+ else:
87
+ return popped(oparg)
88
+
89
+ def get_num_pushed(self, opname: str, oparg: object) -> int:
90
+ pushed = self.pushed.get(opname)
91
+ if pushed is None:
92
+ raise ValueError(
93
+ f"Error, opcode {opname} was not found, please update opcode.stack_effects"
94
+ )
95
+ if isinstance(pushed, int):
96
+ return pushed
97
+ else:
98
+ return pushed(oparg)
99
+
100
+ def def_op(self, name: str, op: int) -> None:
101
+ # Fill in any missing space in the opname list for
102
+ # opargs which are > 255.
103
+ while op >= len(self.opname):
104
+ self.opname.append("<{!r}>".format(op))
105
+ self.opname[op] = name
106
+ self.opmap[name] = op
107
+ setattr(self, name, op)
108
+
109
+ def name_op(self, name: str, op: int) -> None:
110
+ self.def_op(name, op)
111
+ self.hasname.add(op)
112
+
113
+ def jrel_op(self, name: str, op: int) -> None:
114
+ self.def_op(name, op)
115
+ self.hasjrel.add(op)
116
+
117
+ def jabs_op(self, name: str, op: int) -> None:
118
+ self.def_op(name, op)
119
+ self.hasjabs.add(op)
120
+
121
+ def has_jump(self, op: int) -> bool:
122
+ return op in self.hasjrel or op in self.hasjabs
123
+
124
+ def shadow_op(self, name: str, op: int) -> None:
125
+ self.def_op(name, op)
126
+ self.shadowop.add(op)
127
+
128
+ def remove_op(self, opname: str) -> None:
129
+ op = self.opmap[opname]
130
+ self.hasconst.discard(opname)
131
+ self.hasname.discard(op)
132
+ self.hasjrel.discard(op)
133
+ self.hasjabs.discard(op)
134
+ self.haslocal.discard(op)
135
+ self.hascompare.discard(op)
136
+ self.hasfree.discard(op)
137
+ self.shadowop.discard(op)
138
+ self.opmap.pop(opname)
139
+ self.opname[op] = None # pyre-ignore[6]
140
+ self.stack_effects.pop(opname)
141
+ delattr(self, opname)
142
+
143
+ def copy(self) -> "Opcode":
144
+ result = Opcode()
145
+ result.hasconst = self.hasconst.copy()
146
+ result.hasname = self.hasname.copy()
147
+ result.hasjrel = self.hasjrel.copy()
148
+ result.hasjabs = self.hasjabs.copy()
149
+ result.haslocal = self.haslocal.copy()
150
+ result.hascompare = self.hascompare.copy()
151
+ result.hasfree = self.hasfree.copy()
152
+ result.shadowop = self.shadowop.copy()
153
+ result.opmap = self.opmap.copy()
154
+ result.opname = self.opname.copy()
155
+ result.stack_effects = self.stack_effects.copy()
156
+ for name, op in self.opmap.items():
157
+ setattr(result, name, op)
158
+ return result