pycforge 0.15.2__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 (221) hide show
  1. pycforge/__init__.py +8 -0
  2. pycforge/__main__.py +2 -0
  3. pycforge/_version.py +1 -0
  4. pycforge/converter/__init__.py +0 -0
  5. pycforge/converter/analysis/__init__.py +5 -0
  6. pycforge/converter/analysis/functions.py +723 -0
  7. pycforge/converter/analysis/model.py +158 -0
  8. pycforge/converter/analysis/planning.py +464 -0
  9. pycforge/converter/analysis/stage.py +1976 -0
  10. pycforge/converter/analysis/symbols.py +237 -0
  11. pycforge/converter/analysis/validation.py +2166 -0
  12. pycforge/converter/c_output/__init__.py +2 -0
  13. pycforge/converter/c_output/conformance.py +297 -0
  14. pycforge/converter/c_output/renderer.py +220 -0
  15. pycforge/converter/conditional_regions/__init__.py +71 -0
  16. pycforge/converter/conditional_regions/analysis.py +481 -0
  17. pycforge/converter/conditional_regions/lowering.py +579 -0
  18. pycforge/converter/conditional_regions/model.py +243 -0
  19. pycforge/converter/conditional_regions/validation.py +690 -0
  20. pycforge/converter/containers/__init__.py +19 -0
  21. pycforge/converter/containers/analysis.py +542 -0
  22. pycforge/converter/containers/lowering.py +290 -0
  23. pycforge/converter/containers/model.py +146 -0
  24. pycforge/converter/contracts/__init__.py +0 -0
  25. pycforge/converter/contracts/configuration.py +178 -0
  26. pycforge/converter/contracts/identifiers.py +68 -0
  27. pycforge/converter/contracts/versions.py +71 -0
  28. pycforge/converter/core/__init__.py +0 -0
  29. pycforge/converter/core/artifact_io.py +87 -0
  30. pycforge/converter/core/cancellation.py +7 -0
  31. pycforge/converter/core/canonicalization.py +254 -0
  32. pycforge/converter/core/context.py +13 -0
  33. pycforge/converter/core/diagnostics.py +95 -0
  34. pycforge/converter/core/enums.py +23 -0
  35. pycforge/converter/core/fingerprint.py +22 -0
  36. pycforge/converter/core/pipeline.py +8 -0
  37. pycforge/converter/core/progress.py +25 -0
  38. pycforge/converter/core/request.py +50 -0
  39. pycforge/converter/core/resource_policy.py +31 -0
  40. pycforge/converter/core/result.py +23 -0
  41. pycforge/converter/core/serialization.py +36 -0
  42. pycforge/converter/core/stage.py +10 -0
  43. pycforge/converter/core/stage_artifact.py +80 -0
  44. pycforge/converter/core/stage_outcome.py +15 -0
  45. pycforge/converter/decision_trace/__init__.py +0 -0
  46. pycforge/converter/decision_trace/recorder.py +52 -0
  47. pycforge/converter/facade.py +459 -0
  48. pycforge/converter/frontend/__init__.py +4 -0
  49. pycforge/converter/frontend/normalizer.py +59 -0
  50. pycforge/converter/frontend/parser.py +20 -0
  51. pycforge/converter/frontend/source_document.py +93 -0
  52. pycforge/converter/frontend/stages.py +518 -0
  53. pycforge/converter/frontend/validation.py +76 -0
  54. pycforge/converter/io/__init__.py +0 -0
  55. pycforge/converter/io/atomic_writer.py +33 -0
  56. pycforge/converter/ir/__init__.py +1 -0
  57. pycforge/converter/ir/c_ir/__init__.py +4 -0
  58. pycforge/converter/ir/c_ir/builder.py +26 -0
  59. pycforge/converter/ir/c_ir/model.py +318 -0
  60. pycforge/converter/ir/c_ir/serialization.py +88 -0
  61. pycforge/converter/ir/c_ir/validation.py +834 -0
  62. pycforge/converter/ir/python_ir/__init__.py +17 -0
  63. pycforge/converter/ir/python_ir/nodes.py +86 -0
  64. pycforge/converter/keyword_calls/__init__.py +68 -0
  65. pycforge/converter/keyword_calls/analysis.py +458 -0
  66. pycforge/converter/keyword_calls/lowering.py +271 -0
  67. pycforge/converter/keyword_calls/model.py +304 -0
  68. pycforge/converter/keyword_calls/validation.py +802 -0
  69. pycforge/converter/keyword_only_calls/__init__.py +68 -0
  70. pycforge/converter/keyword_only_calls/analysis.py +640 -0
  71. pycforge/converter/keyword_only_calls/lowering.py +376 -0
  72. pycforge/converter/keyword_only_calls/model.py +328 -0
  73. pycforge/converter/keyword_only_calls/validation.py +1357 -0
  74. pycforge/converter/lowering.py +1000 -0
  75. pycforge/converter/modules/__init__.py +13 -0
  76. pycforge/converter/modules/analysis.py +1250 -0
  77. pycforge/converter/modules/lowering.py +200 -0
  78. pycforge/converter/modules/model.py +73 -0
  79. pycforge/converter/modules/stage.py +192 -0
  80. pycforge/converter/numeric_semantics/__init__.py +23 -0
  81. pycforge/converter/numeric_semantics/analysis.py +420 -0
  82. pycforge/converter/numeric_semantics/lowering.py +153 -0
  83. pycforge/converter/numeric_semantics/model.py +123 -0
  84. pycforge/converter/records/__init__.py +34 -0
  85. pycforge/converter/records/analysis.py +1394 -0
  86. pycforge/converter/records/lowering.py +393 -0
  87. pycforge/converter/records/model.py +319 -0
  88. pycforge/converter/rules/__init__.py +3 -0
  89. pycforge/converter/support_templates/__init__.py +49 -0
  90. pycforge/converter/support_templates/assembly.py +106 -0
  91. pycforge/converter/support_templates/factories.py +348 -0
  92. pycforge/converter/support_templates/model.py +159 -0
  93. pycforge/converter/support_templates/registry.py +388 -0
  94. pycforge/converter/telemetry/__init__.py +0 -0
  95. pycforge/converter/telemetry/sink.py +39 -0
  96. pycforge/ide/__init__.py +19 -0
  97. pycforge/ide/__main__.py +5 -0
  98. pycforge/ide/_worker_event_codec.py +276 -0
  99. pycforge/ide/_worker_protocol_json.py +197 -0
  100. pycforge/ide/_worker_protocol_types.py +90 -0
  101. pycforge/ide/_worker_request_codec.py +200 -0
  102. pycforge/ide/_worker_request_data.py +260 -0
  103. pycforge/ide/_worker_result_data.py +343 -0
  104. pycforge/ide/action_contract.py +469 -0
  105. pycforge/ide/action_validation.py +229 -0
  106. pycforge/ide/command_palette.py +223 -0
  107. pycforge/ide/controller.py +904 -0
  108. pycforge/ide/controller_conversion.py +546 -0
  109. pycforge/ide/controller_io.py +205 -0
  110. pycforge/ide/editor.py +951 -0
  111. pycforge/ide/editor_commands_qt.py +274 -0
  112. pycforge/ide/editor_lexical.py +43 -0
  113. pycforge/ide/editor_sidebars.py +236 -0
  114. pycforge/ide/editor_syntax.py +243 -0
  115. pycforge/ide/find_replace.py +535 -0
  116. pycforge/ide/icons.py +91 -0
  117. pycforge/ide/io_service.py +196 -0
  118. pycforge/ide/model.py +164 -0
  119. pycforge/ide/panels.py +903 -0
  120. pycforge/ide/positions.py +220 -0
  121. pycforge/ide/process_worker.py +130 -0
  122. pycforge/ide/qt.py +230 -0
  123. pycforge/ide/qt_actions.py +418 -0
  124. pycforge/ide/qt_close.py +169 -0
  125. pycforge/ide/qt_command_palette.py +297 -0
  126. pycforge/ide/qt_contract.py +220 -0
  127. pycforge/ide/qt_documents.py +590 -0
  128. pycforge/ide/qt_editor_buffers.py +113 -0
  129. pycforge/ide/qt_editor_surfaces.py +112 -0
  130. pycforge/ide/qt_menus.py +324 -0
  131. pycforge/ide/qt_projection.py +500 -0
  132. pycforge/ide/qt_shell.py +348 -0
  133. pycforge/ide/qt_shell_interactions.py +320 -0
  134. pycforge/ide/qt_state.py +393 -0
  135. pycforge/ide/qt_workspace_features.py +398 -0
  136. pycforge/ide/qt_workspace_navigation.py +208 -0
  137. pycforge/ide/qt_workspace_observers.py +173 -0
  138. pycforge/ide/qt_workspace_panels.py +545 -0
  139. pycforge/ide/qt_workspace_widgets.py +228 -0
  140. pycforge/ide/resources/icons/about.svg +1 -0
  141. pycforge/ide/resources/icons/add-document.svg +1 -0
  142. pycforge/ide/resources/icons/brand-mark.svg +1 -0
  143. pycforge/ide/resources/icons/bundle-search.svg +1 -0
  144. pycforge/ide/resources/icons/cancel.svg +1 -0
  145. pycforge/ide/resources/icons/check.svg +1 -0
  146. pycforge/ide/resources/icons/chevron-right.svg +1 -0
  147. pycforge/ide/resources/icons/close.svg +1 -0
  148. pycforge/ide/resources/icons/collapse-all.svg +1 -0
  149. pycforge/ide/resources/icons/command-palette.svg +1 -0
  150. pycforge/ide/resources/icons/convert.svg +1 -0
  151. pycforge/ide/resources/icons/copy.svg +1 -0
  152. pycforge/ide/resources/icons/cut.svg +1 -0
  153. pycforge/ide/resources/icons/decision-trace.svg +1 -0
  154. pycforge/ide/resources/icons/details.svg +1 -0
  155. pycforge/ide/resources/icons/diagnostics.svg +1 -0
  156. pycforge/ide/resources/icons/duplicate-line.svg +1 -0
  157. pycforge/ide/resources/icons/exit.svg +1 -0
  158. pycforge/ide/resources/icons/expand-all.svg +1 -0
  159. pycforge/ide/resources/icons/export.svg +1 -0
  160. pycforge/ide/resources/icons/find.svg +1 -0
  161. pycforge/ide/resources/icons/go-to-line.svg +1 -0
  162. pycforge/ide/resources/icons/go-to-output.svg +1 -0
  163. pycforge/ide/resources/icons/go-to-source.svg +1 -0
  164. pycforge/ide/resources/icons/history.svg +1 -0
  165. pycforge/ide/resources/icons/indent.svg +1 -0
  166. pycforge/ide/resources/icons/link-c.svg +1 -0
  167. pycforge/ide/resources/icons/mappings.svg +1 -0
  168. pycforge/ide/resources/icons/module.svg +1 -0
  169. pycforge/ide/resources/icons/move-down.svg +1 -0
  170. pycforge/ide/resources/icons/move-line-down.svg +1 -0
  171. pycforge/ide/resources/icons/move-line-up.svg +1 -0
  172. pycforge/ide/resources/icons/move-up.svg +1 -0
  173. pycforge/ide/resources/icons/next.svg +1 -0
  174. pycforge/ide/resources/icons/open.svg +1 -0
  175. pycforge/ide/resources/icons/outdent.svg +1 -0
  176. pycforge/ide/resources/icons/outline.svg +1 -0
  177. pycforge/ide/resources/icons/paste.svg +1 -0
  178. pycforge/ide/resources/icons/previous.svg +1 -0
  179. pycforge/ide/resources/icons/primary-module.svg +1 -0
  180. pycforge/ide/resources/icons/redo.svg +1 -0
  181. pycforge/ide/resources/icons/remove-document.svg +1 -0
  182. pycforge/ide/resources/icons/replace.svg +1 -0
  183. pycforge/ide/resources/icons/save-as.svg +1 -0
  184. pycforge/ide/resources/icons/save.svg +1 -0
  185. pycforge/ide/resources/icons/select-all.svg +1 -0
  186. pycforge/ide/resources/icons/settings.svg +1 -0
  187. pycforge/ide/resources/icons/show-c.svg +1 -0
  188. pycforge/ide/resources/icons/split-view.svg +1 -0
  189. pycforge/ide/resources/icons/summary.svg +1 -0
  190. pycforge/ide/resources/icons/telemetry.svg +1 -0
  191. pycforge/ide/resources/icons/toggle-comment.svg +1 -0
  192. pycforge/ide/resources/icons/toggle-fold.svg +1 -0
  193. pycforge/ide/resources/icons/undo.svg +1 -0
  194. pycforge/ide/resources/icons/whitespace.svg +1 -0
  195. pycforge/ide/revisions.py +400 -0
  196. pycforge/ide/search_service.py +280 -0
  197. pycforge/ide/session_history.py +150 -0
  198. pycforge/ide/source_editing.py +417 -0
  199. pycforge/ide/source_structure.py +558 -0
  200. pycforge/ide/source_structure_async.py +191 -0
  201. pycforge/ide/supervisor.py +503 -0
  202. pycforge/ide/theme.py +119 -0
  203. pycforge/ide/theme_stylesheet.py +598 -0
  204. pycforge/ide/theme_workspace_stylesheet.py +155 -0
  205. pycforge/ide/visual_tokens.py +142 -0
  206. pycforge/ide/worker_protocol.py +80 -0
  207. pycforge/ide/workspace_search.py +462 -0
  208. pycforge/ide/workspace_session.py +256 -0
  209. pycforge/laboratory/__init__.py +6 -0
  210. pycforge/laboratory/audits.py +2244 -0
  211. pycforge/laboratory/checkpoint_e.py +2685 -0
  212. pycforge/laboratory/cli.py +119 -0
  213. pycforge/laboratory/exit_codes.py +11 -0
  214. pycforge/laboratory/keyword_audit.py +661 -0
  215. pycforge/laboratory/keyword_only_audit.py +481 -0
  216. pycforge-0.15.2.dist-info/METADATA +209 -0
  217. pycforge-0.15.2.dist-info/RECORD +221 -0
  218. pycforge-0.15.2.dist-info/WHEEL +5 -0
  219. pycforge-0.15.2.dist-info/entry_points.txt +5 -0
  220. pycforge-0.15.2.dist-info/licenses/LICENSE +674 -0
  221. pycforge-0.15.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,319 @@
1
+ """Immutable facts for the Phase 13 bounded static-record profile.
2
+
3
+ This module deliberately describes source semantics only. It has no C IR,
4
+ renderer, allocation, or runtime dependency, which keeps the representation
5
+ gate independently testable before lowering is enabled.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from enum import Enum
12
+ from typing import Any
13
+
14
+ from pycforge.converter.analysis.model import ValueCategory
15
+
16
+
17
+ MAX_RECORD_FIELDS = 64
18
+
19
+
20
+ class RecordValueCategory(str, Enum):
21
+ DEFINITION = "immutable-static-record-definition"
22
+ INSTANCE = "immutable-static-record-like"
23
+
24
+
25
+ class RecordAnalysisError(Exception):
26
+ """Deterministic source rejection raised by static-record analysis."""
27
+
28
+ def __init__(
29
+ self,
30
+ code: str,
31
+ message: str,
32
+ *,
33
+ node_id: str,
34
+ module_id: str,
35
+ document_id: str,
36
+ logical_name: str,
37
+ source_span: dict[str, Any] | None,
38
+ ) -> None:
39
+ super().__init__(message)
40
+ self.code = code
41
+ self.message = message
42
+ self.node_id = node_id
43
+ self.module_id = module_id
44
+ self.document_id = document_id
45
+ self.logical_name = logical_name
46
+ self.source_span = source_span
47
+
48
+ def to_dict(self) -> dict[str, Any]:
49
+ return {
50
+ "code": self.code,
51
+ "message": self.message,
52
+ "node_id": self.node_id,
53
+ "module_id": self.module_id,
54
+ "document_id": self.document_id,
55
+ "logical_name": self.logical_name,
56
+ "source_span": self.source_span,
57
+ }
58
+
59
+
60
+ class RecordAnalysisCanceled(Exception):
61
+ """Internal cooperative-cancellation signal for static-record analysis."""
62
+
63
+
64
+ @dataclass(frozen=True, slots=True)
65
+ class RecordDefinitionFact:
66
+ record_id: str
67
+ class_node_id: str
68
+ class_binding_id: str
69
+ source_name: str
70
+ flattened_name: str
71
+ module_id: str
72
+ document_id: str
73
+ logical_name: str
74
+ field_ids: tuple[str, ...]
75
+ initializer_id: str
76
+ category: RecordValueCategory
77
+ storage_model: str
78
+ ownership_model: str
79
+ lifetime_model: str
80
+ aliasing_model: str
81
+ cleanup_model: str
82
+ nullability_model: str
83
+ mutable: bool
84
+
85
+ def to_dict(self) -> dict[str, Any]:
86
+ return {
87
+ "record_id": self.record_id,
88
+ "class_node_id": self.class_node_id,
89
+ "class_binding_id": self.class_binding_id,
90
+ "source_name": self.source_name,
91
+ "flattened_name": self.flattened_name,
92
+ "module_id": self.module_id,
93
+ "document_id": self.document_id,
94
+ "logical_name": self.logical_name,
95
+ "field_ids": list(self.field_ids),
96
+ "initializer_id": self.initializer_id,
97
+ "category": self.category.value,
98
+ "storage_model": self.storage_model,
99
+ "ownership_model": self.ownership_model,
100
+ "lifetime_model": self.lifetime_model,
101
+ "aliasing_model": self.aliasing_model,
102
+ "cleanup_model": self.cleanup_model,
103
+ "nullability_model": self.nullability_model,
104
+ "mutable": self.mutable,
105
+ }
106
+
107
+
108
+ @dataclass(frozen=True, slots=True)
109
+ class RecordFieldFact:
110
+ field_id: str
111
+ record_id: str
112
+ class_node_id: str
113
+ declaration_node_id: str
114
+ target_node_id: str
115
+ annotation_node_id: str
116
+ source_name: str
117
+ ordinal: int
118
+ category: ValueCategory
119
+ module_id: str
120
+ document_id: str
121
+ logical_name: str
122
+ mutable: bool
123
+
124
+ def to_dict(self) -> dict[str, Any]:
125
+ return {
126
+ "field_id": self.field_id,
127
+ "record_id": self.record_id,
128
+ "class_node_id": self.class_node_id,
129
+ "declaration_node_id": self.declaration_node_id,
130
+ "target_node_id": self.target_node_id,
131
+ "annotation_node_id": self.annotation_node_id,
132
+ "source_name": self.source_name,
133
+ "ordinal": self.ordinal,
134
+ "category": self.category.value,
135
+ "module_id": self.module_id,
136
+ "document_id": self.document_id,
137
+ "logical_name": self.logical_name,
138
+ "mutable": self.mutable,
139
+ }
140
+
141
+
142
+ @dataclass(frozen=True, slots=True)
143
+ class RecordInitializerFact:
144
+ initializer_id: str
145
+ record_id: str
146
+ function_node_id: str
147
+ arguments_node_id: str
148
+ self_parameter_node_id: str
149
+ parameter_node_ids: tuple[str, ...]
150
+ assignment_node_ids: tuple[str, ...]
151
+ field_ids: tuple[str, ...]
152
+ module_id: str
153
+ document_id: str
154
+ logical_name: str
155
+ receiver_model: str
156
+ evaluation_order: str
157
+ initialization_completeness: str
158
+
159
+ def to_dict(self) -> dict[str, Any]:
160
+ return {
161
+ "initializer_id": self.initializer_id,
162
+ "record_id": self.record_id,
163
+ "function_node_id": self.function_node_id,
164
+ "arguments_node_id": self.arguments_node_id,
165
+ "self_parameter_node_id": self.self_parameter_node_id,
166
+ "parameter_node_ids": list(self.parameter_node_ids),
167
+ "assignment_node_ids": list(self.assignment_node_ids),
168
+ "field_ids": list(self.field_ids),
169
+ "module_id": self.module_id,
170
+ "document_id": self.document_id,
171
+ "logical_name": self.logical_name,
172
+ "receiver_model": self.receiver_model,
173
+ "evaluation_order": self.evaluation_order,
174
+ "initialization_completeness": self.initialization_completeness,
175
+ }
176
+
177
+
178
+ @dataclass(frozen=True, slots=True)
179
+ class RecordInstanceFact:
180
+ instance_id: str
181
+ record_id: str
182
+ class_node_id: str
183
+ owner_function_node_id: str
184
+ construction_node_id: str
185
+ assignment_node_id: str
186
+ target_node_id: str
187
+ binding_id: str
188
+ source_name: str
189
+ argument_node_ids: tuple[str, ...]
190
+ module_id: str
191
+ document_id: str
192
+ logical_name: str
193
+ category: RecordValueCategory
194
+ storage_model: str
195
+ ownership_model: str
196
+ lifetime_model: str
197
+ aliasing_model: str
198
+ cleanup_model: str
199
+ nullability_model: str
200
+ allocation_model: str
201
+ mutable: bool
202
+
203
+ def to_dict(self) -> dict[str, Any]:
204
+ return {
205
+ "instance_id": self.instance_id,
206
+ "record_id": self.record_id,
207
+ "class_node_id": self.class_node_id,
208
+ "owner_function_node_id": self.owner_function_node_id,
209
+ "construction_node_id": self.construction_node_id,
210
+ "assignment_node_id": self.assignment_node_id,
211
+ "target_node_id": self.target_node_id,
212
+ "binding_id": self.binding_id,
213
+ "source_name": self.source_name,
214
+ "argument_node_ids": list(self.argument_node_ids),
215
+ "module_id": self.module_id,
216
+ "document_id": self.document_id,
217
+ "logical_name": self.logical_name,
218
+ "category": self.category.value,
219
+ "storage_model": self.storage_model,
220
+ "ownership_model": self.ownership_model,
221
+ "lifetime_model": self.lifetime_model,
222
+ "aliasing_model": self.aliasing_model,
223
+ "cleanup_model": self.cleanup_model,
224
+ "nullability_model": self.nullability_model,
225
+ "allocation_model": self.allocation_model,
226
+ "mutable": self.mutable,
227
+ }
228
+
229
+
230
+ @dataclass(frozen=True, slots=True)
231
+ class RecordInstanceBindingFact:
232
+ binding_id: str
233
+ instance_id: str
234
+ record_id: str
235
+ source_name: str
236
+ declaration_node_id: str
237
+ occurrence_node_ids: tuple[str, ...]
238
+ allowed_field_access_node_ids: tuple[str, ...]
239
+ owner_function_node_id: str
240
+ module_id: str
241
+ document_id: str
242
+ logical_name: str
243
+ category: RecordValueCategory
244
+ single_assignment: bool
245
+ noalias: bool
246
+ escapes: bool
247
+
248
+ def to_dict(self) -> dict[str, Any]:
249
+ return {
250
+ "binding_id": self.binding_id,
251
+ "instance_id": self.instance_id,
252
+ "record_id": self.record_id,
253
+ "source_name": self.source_name,
254
+ "declaration_node_id": self.declaration_node_id,
255
+ "occurrence_node_ids": list(self.occurrence_node_ids),
256
+ "allowed_field_access_node_ids": list(self.allowed_field_access_node_ids),
257
+ "owner_function_node_id": self.owner_function_node_id,
258
+ "module_id": self.module_id,
259
+ "document_id": self.document_id,
260
+ "logical_name": self.logical_name,
261
+ "category": self.category.value,
262
+ "single_assignment": self.single_assignment,
263
+ "noalias": self.noalias,
264
+ "escapes": self.escapes,
265
+ }
266
+
267
+
268
+ @dataclass(frozen=True, slots=True)
269
+ class RecordFieldAccessFact:
270
+ access_node_id: str
271
+ instance_id: str
272
+ binding_id: str
273
+ record_id: str
274
+ field_id: str
275
+ field_name: str
276
+ field_category: ValueCategory
277
+ owner_function_node_id: str
278
+ module_id: str
279
+ document_id: str
280
+ logical_name: str
281
+ access_mode: str
282
+ statically_bound: bool
283
+
284
+ def to_dict(self) -> dict[str, Any]:
285
+ return {
286
+ "access_node_id": self.access_node_id,
287
+ "instance_id": self.instance_id,
288
+ "binding_id": self.binding_id,
289
+ "record_id": self.record_id,
290
+ "field_id": self.field_id,
291
+ "field_name": self.field_name,
292
+ "field_category": self.field_category.value,
293
+ "owner_function_node_id": self.owner_function_node_id,
294
+ "module_id": self.module_id,
295
+ "document_id": self.document_id,
296
+ "logical_name": self.logical_name,
297
+ "access_mode": self.access_mode,
298
+ "statically_bound": self.statically_bound,
299
+ }
300
+
301
+
302
+ @dataclass(frozen=True, slots=True)
303
+ class StaticRecordAnalysis:
304
+ definitions: tuple[RecordDefinitionFact, ...]
305
+ fields: tuple[RecordFieldFact, ...]
306
+ initializers: tuple[RecordInitializerFact, ...]
307
+ instances: tuple[RecordInstanceFact, ...]
308
+ bindings: tuple[RecordInstanceBindingFact, ...]
309
+ accesses: tuple[RecordFieldAccessFact, ...]
310
+
311
+ def to_dict(self) -> dict[str, Any]:
312
+ return {
313
+ "definitions": [item.to_dict() for item in self.definitions],
314
+ "fields": [item.to_dict() for item in self.fields],
315
+ "initializers": [item.to_dict() for item in self.initializers],
316
+ "instances": [item.to_dict() for item in self.instances],
317
+ "bindings": [item.to_dict() for item in self.bindings],
318
+ "accesses": [item.to_dict() for item in self.accesses],
319
+ }
@@ -0,0 +1,3 @@
1
+ """Phase 5 rule-planning contracts. Rules create immutable RulePlans only; lowering begins in Phase 6."""
2
+ from pycforge.converter.analysis.planning import FrozenRuleRegistry, RuleDefinition, RulePlan, default_registry
3
+ __all__ = ["FrozenRuleRegistry", "RuleDefinition", "RulePlan", "default_registry"]
@@ -0,0 +1,49 @@
1
+ """Trusted Phase 10 support-template infrastructure."""
2
+
3
+ from .assembly import assemble_translation_unit
4
+ from .factories import (
5
+ FLOOR_DIV_REFERENCE,
6
+ FLOOR_MOD_REFERENCE,
7
+ builtin_definitions,
8
+ floor_div_asset,
9
+ floor_mod_asset,
10
+ )
11
+ from .model import (
12
+ HELPER_INTERFACE_ID,
13
+ HELPER_REGISTRY_VERSION,
14
+ HelperCIRAsset,
15
+ HelperDefinition,
16
+ HelperFailureContract,
17
+ HelperManifestEntry,
18
+ HelperOwnershipContract,
19
+ HelperReference,
20
+ ResolvedHelperPlan,
21
+ )
22
+ from .registry import (
23
+ FrozenHelperRegistry,
24
+ HelperRegistryError,
25
+ HelperResolutionCanceled,
26
+ default_helper_registry,
27
+ )
28
+
29
+ __all__ = [
30
+ "FLOOR_DIV_REFERENCE",
31
+ "FLOOR_MOD_REFERENCE",
32
+ "HELPER_INTERFACE_ID",
33
+ "HELPER_REGISTRY_VERSION",
34
+ "FrozenHelperRegistry",
35
+ "HelperCIRAsset",
36
+ "HelperDefinition",
37
+ "HelperFailureContract",
38
+ "HelperManifestEntry",
39
+ "HelperOwnershipContract",
40
+ "HelperReference",
41
+ "HelperRegistryError",
42
+ "HelperResolutionCanceled",
43
+ "ResolvedHelperPlan",
44
+ "assemble_translation_unit",
45
+ "builtin_definitions",
46
+ "default_helper_registry",
47
+ "floor_div_asset",
48
+ "floor_mod_asset",
49
+ ]
@@ -0,0 +1,106 @@
1
+ """Deterministic translation-unit assembly for resolved helper plans."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pycforge.converter.ir.c_ir import (
6
+ CFunctionDefinition,
7
+ CFunctionPrototype,
8
+ CRecordDefinition,
9
+ CTranslationUnit,
10
+ CTranslationUnitBuilder,
11
+ CONDITIONAL_SCHEMA_VERSION,
12
+ CONTAINER_SCHEMA_VERSION,
13
+ HELPER_SCHEMA_VERSION,
14
+ MODULE_SCHEMA_VERSION,
15
+ NUMERIC_SCHEMA_VERSION,
16
+ RECORD_SCHEMA_VERSION,
17
+ KEYWORD_CALL_SCHEMA_VERSION,
18
+ KEYWORD_ONLY_CALL_SCHEMA_VERSION,
19
+ validate_translation_unit,
20
+ )
21
+
22
+ from .model import ResolvedHelperPlan
23
+ from .registry import HelperRegistryError
24
+
25
+
26
+ def assemble_translation_unit(
27
+ source_unit: CTranslationUnit,
28
+ plan: ResolvedHelperPlan,
29
+ ) -> CTranslationUnit:
30
+ """Insert each resolved helper once without changing an empty-plan unit."""
31
+
32
+ if source_unit.target_contract != plan.target_contract:
33
+ raise HelperRegistryError(
34
+ "PYC3304",
35
+ "resolved helper target does not match the source translation unit",
36
+ )
37
+ if not plan.assets:
38
+ return source_unit
39
+
40
+ includes_by_key = {}
41
+ for include in sorted(
42
+ source_unit.includes + tuple(item for asset in plan.assets for item in asset.includes),
43
+ key=lambda item: (not item.system, item.header, item.node_id),
44
+ ):
45
+ includes_by_key.setdefault((include.header, include.system), include)
46
+
47
+ source_prototypes = tuple(
48
+ item for item in source_unit.declarations if isinstance(item, CFunctionPrototype)
49
+ )
50
+ source_definitions = tuple(
51
+ item for item in source_unit.declarations if isinstance(item, CFunctionDefinition)
52
+ )
53
+ source_other = tuple(
54
+ item
55
+ for item in source_unit.declarations
56
+ if not isinstance(item, (CFunctionPrototype, CFunctionDefinition))
57
+ )
58
+ source_records = tuple(
59
+ item for item in source_other if isinstance(item, CRecordDefinition)
60
+ )
61
+ source_variables = tuple(
62
+ item for item in source_other if not isinstance(item, CRecordDefinition)
63
+ )
64
+ helper_prototypes = tuple(asset.prototype for asset in plan.assets)
65
+ helper_definitions = tuple(asset.definition for asset in plan.assets)
66
+
67
+ builder = CTranslationUnitBuilder(
68
+ source_unit.target_contract,
69
+ node_id=source_unit.node_id,
70
+ provenance=source_unit.provenance,
71
+ schema_version=(
72
+ source_unit.schema_version
73
+ if source_unit.schema_version in {
74
+ CONTAINER_SCHEMA_VERSION,
75
+ MODULE_SCHEMA_VERSION,
76
+ RECORD_SCHEMA_VERSION,
77
+ NUMERIC_SCHEMA_VERSION,
78
+ CONDITIONAL_SCHEMA_VERSION,
79
+ KEYWORD_CALL_SCHEMA_VERSION,
80
+ KEYWORD_ONLY_CALL_SCHEMA_VERSION,
81
+ }
82
+ else HELPER_SCHEMA_VERSION
83
+ ),
84
+ module_manifest=source_unit.module_manifest,
85
+ module_order=source_unit.module_order,
86
+ module_dependencies=source_unit.module_dependencies,
87
+ )
88
+ for include in includes_by_key.values():
89
+ builder.add_include(include)
90
+ for declaration in (
91
+ source_records
92
+ + helper_prototypes
93
+ + source_prototypes
94
+ + source_variables
95
+ + helper_definitions
96
+ + source_definitions
97
+ ):
98
+ builder.add_declaration(declaration)
99
+ assembled = builder.build()
100
+ validation = validate_translation_unit(assembled)
101
+ if not validation.accepted:
102
+ raise HelperRegistryError(
103
+ "PYC3306",
104
+ "helper assembly produced invalid C IR: " + "; ".join(validation.errors),
105
+ )
106
+ return assembled