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.
- pycforge/__init__.py +8 -0
- pycforge/__main__.py +2 -0
- pycforge/_version.py +1 -0
- pycforge/converter/__init__.py +0 -0
- pycforge/converter/analysis/__init__.py +5 -0
- pycforge/converter/analysis/functions.py +723 -0
- pycforge/converter/analysis/model.py +158 -0
- pycforge/converter/analysis/planning.py +464 -0
- pycforge/converter/analysis/stage.py +1976 -0
- pycforge/converter/analysis/symbols.py +237 -0
- pycforge/converter/analysis/validation.py +2166 -0
- pycforge/converter/c_output/__init__.py +2 -0
- pycforge/converter/c_output/conformance.py +297 -0
- pycforge/converter/c_output/renderer.py +220 -0
- pycforge/converter/conditional_regions/__init__.py +71 -0
- pycforge/converter/conditional_regions/analysis.py +481 -0
- pycforge/converter/conditional_regions/lowering.py +579 -0
- pycforge/converter/conditional_regions/model.py +243 -0
- pycforge/converter/conditional_regions/validation.py +690 -0
- pycforge/converter/containers/__init__.py +19 -0
- pycforge/converter/containers/analysis.py +542 -0
- pycforge/converter/containers/lowering.py +290 -0
- pycforge/converter/containers/model.py +146 -0
- pycforge/converter/contracts/__init__.py +0 -0
- pycforge/converter/contracts/configuration.py +178 -0
- pycforge/converter/contracts/identifiers.py +68 -0
- pycforge/converter/contracts/versions.py +71 -0
- pycforge/converter/core/__init__.py +0 -0
- pycforge/converter/core/artifact_io.py +87 -0
- pycforge/converter/core/cancellation.py +7 -0
- pycforge/converter/core/canonicalization.py +254 -0
- pycforge/converter/core/context.py +13 -0
- pycforge/converter/core/diagnostics.py +95 -0
- pycforge/converter/core/enums.py +23 -0
- pycforge/converter/core/fingerprint.py +22 -0
- pycforge/converter/core/pipeline.py +8 -0
- pycforge/converter/core/progress.py +25 -0
- pycforge/converter/core/request.py +50 -0
- pycforge/converter/core/resource_policy.py +31 -0
- pycforge/converter/core/result.py +23 -0
- pycforge/converter/core/serialization.py +36 -0
- pycforge/converter/core/stage.py +10 -0
- pycforge/converter/core/stage_artifact.py +80 -0
- pycforge/converter/core/stage_outcome.py +15 -0
- pycforge/converter/decision_trace/__init__.py +0 -0
- pycforge/converter/decision_trace/recorder.py +52 -0
- pycforge/converter/facade.py +459 -0
- pycforge/converter/frontend/__init__.py +4 -0
- pycforge/converter/frontend/normalizer.py +59 -0
- pycforge/converter/frontend/parser.py +20 -0
- pycforge/converter/frontend/source_document.py +93 -0
- pycforge/converter/frontend/stages.py +518 -0
- pycforge/converter/frontend/validation.py +76 -0
- pycforge/converter/io/__init__.py +0 -0
- pycforge/converter/io/atomic_writer.py +33 -0
- pycforge/converter/ir/__init__.py +1 -0
- pycforge/converter/ir/c_ir/__init__.py +4 -0
- pycforge/converter/ir/c_ir/builder.py +26 -0
- pycforge/converter/ir/c_ir/model.py +318 -0
- pycforge/converter/ir/c_ir/serialization.py +88 -0
- pycforge/converter/ir/c_ir/validation.py +834 -0
- pycforge/converter/ir/python_ir/__init__.py +17 -0
- pycforge/converter/ir/python_ir/nodes.py +86 -0
- pycforge/converter/keyword_calls/__init__.py +68 -0
- pycforge/converter/keyword_calls/analysis.py +458 -0
- pycforge/converter/keyword_calls/lowering.py +271 -0
- pycforge/converter/keyword_calls/model.py +304 -0
- pycforge/converter/keyword_calls/validation.py +802 -0
- pycforge/converter/keyword_only_calls/__init__.py +68 -0
- pycforge/converter/keyword_only_calls/analysis.py +640 -0
- pycforge/converter/keyword_only_calls/lowering.py +376 -0
- pycforge/converter/keyword_only_calls/model.py +328 -0
- pycforge/converter/keyword_only_calls/validation.py +1357 -0
- pycforge/converter/lowering.py +1000 -0
- pycforge/converter/modules/__init__.py +13 -0
- pycforge/converter/modules/analysis.py +1250 -0
- pycforge/converter/modules/lowering.py +200 -0
- pycforge/converter/modules/model.py +73 -0
- pycforge/converter/modules/stage.py +192 -0
- pycforge/converter/numeric_semantics/__init__.py +23 -0
- pycforge/converter/numeric_semantics/analysis.py +420 -0
- pycforge/converter/numeric_semantics/lowering.py +153 -0
- pycforge/converter/numeric_semantics/model.py +123 -0
- pycforge/converter/records/__init__.py +34 -0
- pycforge/converter/records/analysis.py +1394 -0
- pycforge/converter/records/lowering.py +393 -0
- pycforge/converter/records/model.py +319 -0
- pycforge/converter/rules/__init__.py +3 -0
- pycforge/converter/support_templates/__init__.py +49 -0
- pycforge/converter/support_templates/assembly.py +106 -0
- pycforge/converter/support_templates/factories.py +348 -0
- pycforge/converter/support_templates/model.py +159 -0
- pycforge/converter/support_templates/registry.py +388 -0
- pycforge/converter/telemetry/__init__.py +0 -0
- pycforge/converter/telemetry/sink.py +39 -0
- pycforge/ide/__init__.py +19 -0
- pycforge/ide/__main__.py +5 -0
- pycforge/ide/_worker_event_codec.py +276 -0
- pycforge/ide/_worker_protocol_json.py +197 -0
- pycforge/ide/_worker_protocol_types.py +90 -0
- pycforge/ide/_worker_request_codec.py +200 -0
- pycforge/ide/_worker_request_data.py +260 -0
- pycforge/ide/_worker_result_data.py +343 -0
- pycforge/ide/action_contract.py +469 -0
- pycforge/ide/action_validation.py +229 -0
- pycforge/ide/command_palette.py +223 -0
- pycforge/ide/controller.py +904 -0
- pycforge/ide/controller_conversion.py +546 -0
- pycforge/ide/controller_io.py +205 -0
- pycforge/ide/editor.py +951 -0
- pycforge/ide/editor_commands_qt.py +274 -0
- pycforge/ide/editor_lexical.py +43 -0
- pycforge/ide/editor_sidebars.py +236 -0
- pycforge/ide/editor_syntax.py +243 -0
- pycforge/ide/find_replace.py +535 -0
- pycforge/ide/icons.py +91 -0
- pycforge/ide/io_service.py +196 -0
- pycforge/ide/model.py +164 -0
- pycforge/ide/panels.py +903 -0
- pycforge/ide/positions.py +220 -0
- pycforge/ide/process_worker.py +130 -0
- pycforge/ide/qt.py +230 -0
- pycforge/ide/qt_actions.py +418 -0
- pycforge/ide/qt_close.py +169 -0
- pycforge/ide/qt_command_palette.py +297 -0
- pycforge/ide/qt_contract.py +220 -0
- pycforge/ide/qt_documents.py +590 -0
- pycforge/ide/qt_editor_buffers.py +113 -0
- pycforge/ide/qt_editor_surfaces.py +112 -0
- pycforge/ide/qt_menus.py +324 -0
- pycforge/ide/qt_projection.py +500 -0
- pycforge/ide/qt_shell.py +348 -0
- pycforge/ide/qt_shell_interactions.py +320 -0
- pycforge/ide/qt_state.py +393 -0
- pycforge/ide/qt_workspace_features.py +398 -0
- pycforge/ide/qt_workspace_navigation.py +208 -0
- pycforge/ide/qt_workspace_observers.py +173 -0
- pycforge/ide/qt_workspace_panels.py +545 -0
- pycforge/ide/qt_workspace_widgets.py +228 -0
- pycforge/ide/resources/icons/about.svg +1 -0
- pycforge/ide/resources/icons/add-document.svg +1 -0
- pycforge/ide/resources/icons/brand-mark.svg +1 -0
- pycforge/ide/resources/icons/bundle-search.svg +1 -0
- pycforge/ide/resources/icons/cancel.svg +1 -0
- pycforge/ide/resources/icons/check.svg +1 -0
- pycforge/ide/resources/icons/chevron-right.svg +1 -0
- pycforge/ide/resources/icons/close.svg +1 -0
- pycforge/ide/resources/icons/collapse-all.svg +1 -0
- pycforge/ide/resources/icons/command-palette.svg +1 -0
- pycforge/ide/resources/icons/convert.svg +1 -0
- pycforge/ide/resources/icons/copy.svg +1 -0
- pycforge/ide/resources/icons/cut.svg +1 -0
- pycforge/ide/resources/icons/decision-trace.svg +1 -0
- pycforge/ide/resources/icons/details.svg +1 -0
- pycforge/ide/resources/icons/diagnostics.svg +1 -0
- pycforge/ide/resources/icons/duplicate-line.svg +1 -0
- pycforge/ide/resources/icons/exit.svg +1 -0
- pycforge/ide/resources/icons/expand-all.svg +1 -0
- pycforge/ide/resources/icons/export.svg +1 -0
- pycforge/ide/resources/icons/find.svg +1 -0
- pycforge/ide/resources/icons/go-to-line.svg +1 -0
- pycforge/ide/resources/icons/go-to-output.svg +1 -0
- pycforge/ide/resources/icons/go-to-source.svg +1 -0
- pycforge/ide/resources/icons/history.svg +1 -0
- pycforge/ide/resources/icons/indent.svg +1 -0
- pycforge/ide/resources/icons/link-c.svg +1 -0
- pycforge/ide/resources/icons/mappings.svg +1 -0
- pycforge/ide/resources/icons/module.svg +1 -0
- pycforge/ide/resources/icons/move-down.svg +1 -0
- pycforge/ide/resources/icons/move-line-down.svg +1 -0
- pycforge/ide/resources/icons/move-line-up.svg +1 -0
- pycforge/ide/resources/icons/move-up.svg +1 -0
- pycforge/ide/resources/icons/next.svg +1 -0
- pycforge/ide/resources/icons/open.svg +1 -0
- pycforge/ide/resources/icons/outdent.svg +1 -0
- pycforge/ide/resources/icons/outline.svg +1 -0
- pycforge/ide/resources/icons/paste.svg +1 -0
- pycforge/ide/resources/icons/previous.svg +1 -0
- pycforge/ide/resources/icons/primary-module.svg +1 -0
- pycforge/ide/resources/icons/redo.svg +1 -0
- pycforge/ide/resources/icons/remove-document.svg +1 -0
- pycforge/ide/resources/icons/replace.svg +1 -0
- pycforge/ide/resources/icons/save-as.svg +1 -0
- pycforge/ide/resources/icons/save.svg +1 -0
- pycforge/ide/resources/icons/select-all.svg +1 -0
- pycforge/ide/resources/icons/settings.svg +1 -0
- pycforge/ide/resources/icons/show-c.svg +1 -0
- pycforge/ide/resources/icons/split-view.svg +1 -0
- pycforge/ide/resources/icons/summary.svg +1 -0
- pycforge/ide/resources/icons/telemetry.svg +1 -0
- pycforge/ide/resources/icons/toggle-comment.svg +1 -0
- pycforge/ide/resources/icons/toggle-fold.svg +1 -0
- pycforge/ide/resources/icons/undo.svg +1 -0
- pycforge/ide/resources/icons/whitespace.svg +1 -0
- pycforge/ide/revisions.py +400 -0
- pycforge/ide/search_service.py +280 -0
- pycforge/ide/session_history.py +150 -0
- pycforge/ide/source_editing.py +417 -0
- pycforge/ide/source_structure.py +558 -0
- pycforge/ide/source_structure_async.py +191 -0
- pycforge/ide/supervisor.py +503 -0
- pycforge/ide/theme.py +119 -0
- pycforge/ide/theme_stylesheet.py +598 -0
- pycforge/ide/theme_workspace_stylesheet.py +155 -0
- pycforge/ide/visual_tokens.py +142 -0
- pycforge/ide/worker_protocol.py +80 -0
- pycforge/ide/workspace_search.py +462 -0
- pycforge/ide/workspace_session.py +256 -0
- pycforge/laboratory/__init__.py +6 -0
- pycforge/laboratory/audits.py +2244 -0
- pycforge/laboratory/checkpoint_e.py +2685 -0
- pycforge/laboratory/cli.py +119 -0
- pycforge/laboratory/exit_codes.py +11 -0
- pycforge/laboratory/keyword_audit.py +661 -0
- pycforge/laboratory/keyword_only_audit.py +481 -0
- pycforge-0.15.2.dist-info/METADATA +209 -0
- pycforge-0.15.2.dist-info/RECORD +221 -0
- pycforge-0.15.2.dist-info/WHEEL +5 -0
- pycforge-0.15.2.dist-info/entry_points.txt +5 -0
- pycforge-0.15.2.dist-info/licenses/LICENSE +674 -0
- pycforge-0.15.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"""Independent non-executing grammar check for PyCForge's emitted C subset.
|
|
2
|
+
|
|
3
|
+
This module intentionally does not import the C IR model or renderer. It lexes
|
|
4
|
+
and parses the rendered source as a separate acceptance boundary.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
|
|
12
|
+
from pycforge.converter.contracts.identifiers import (
|
|
13
|
+
C11_EXTERNAL_IDENTIFIERS as _C11_EXTERNAL_IDENTIFIERS,
|
|
14
|
+
C_KEYWORDS as _C_KEYWORDS,
|
|
15
|
+
TARGET_RESERVED_NAMES as _TARGET_RESERVED_NAMES,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_TOKEN = re.compile(
|
|
20
|
+
r"""
|
|
21
|
+
(?P<space>\s+)
|
|
22
|
+
| (?P<include>\#[ \t]*include[ \t]*(?:<[^>\n]+>|"[^"\n]+"))
|
|
23
|
+
| (?P<string>"(?:[^"\\\n]|\\(?:x[0-9A-Fa-f]+|[0-7]{1,3}|.))*")
|
|
24
|
+
| (?P<float>(?:(?:[0-9]+\.[0-9]*|\.[0-9]+)(?:[eE][+-]?[0-9]+)?|[0-9]+[eE][+-]?[0-9]+))
|
|
25
|
+
| (?P<int>(?:0|[1-9][0-9]*)(?:ULL|LLU|UL|LU|LL|L|U)?)
|
|
26
|
+
| (?P<identifier>[A-Za-z_][A-Za-z0-9_]*)
|
|
27
|
+
| (?P<operator>->|==|!=|<=|>=|<<|>>|&&|\|\||[{}\[\]();,.=*+\-/%<>!~&|^])
|
|
28
|
+
""",
|
|
29
|
+
re.VERBOSE,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
_BASE_TYPES = {"void","char","int","long","int8_t","uint8_t","int16_t","uint16_t","int32_t","uint32_t","int64_t","uint64_t","bool","double"}
|
|
33
|
+
_QUALIFIERS = {"const", "volatile"}
|
|
34
|
+
_STORAGE = {"static", "extern"}
|
|
35
|
+
_REGISTERED_HEADERS = {"stdint.h", "stdbool.h"}
|
|
36
|
+
_STDINT_BASES = {"int8_t","uint8_t","int16_t","uint16_t","int32_t","uint32_t","int64_t","uint64_t"}
|
|
37
|
+
_BINARY_PRECEDENCE = {
|
|
38
|
+
"||": 1, "&&": 2, "|": 3, "^": 4, "&": 5,
|
|
39
|
+
"==": 6, "!=": 6, "<": 7, "<=": 7, ">": 7, ">=": 7,
|
|
40
|
+
"<<": 8, ">>": 8, "+": 9, "-": 9, "*": 10, "/": 10, "%": 10,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True, slots=True)
|
|
45
|
+
class CTextConformanceResult:
|
|
46
|
+
accepted: bool
|
|
47
|
+
message: str
|
|
48
|
+
token_count: int
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class _ParseError(ValueError):
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class _Parser:
|
|
56
|
+
def __init__(self, tokens: tuple[str, ...]) -> None:
|
|
57
|
+
self.tokens = tokens
|
|
58
|
+
self.position = 0
|
|
59
|
+
self.headers: set[str] = set()
|
|
60
|
+
self.used_bases: set[str] = set()
|
|
61
|
+
self.record_types: set[str] = set()
|
|
62
|
+
|
|
63
|
+
def parse(self) -> None:
|
|
64
|
+
while self._peek().startswith("#"):
|
|
65
|
+
match = re.fullmatch(r"\#[ \t]*include[ \t]*<([^>\n]+)>", self._peek())
|
|
66
|
+
if not match or match.group(1) not in _REGISTERED_HEADERS:
|
|
67
|
+
raise _ParseError("unregistered or non-system include")
|
|
68
|
+
if match.group(1) in self.headers:
|
|
69
|
+
raise _ParseError(f"duplicate include: {match.group(1)}")
|
|
70
|
+
self.headers.add(match.group(1))
|
|
71
|
+
self.position += 1
|
|
72
|
+
while self._peek():
|
|
73
|
+
if self._peek().startswith("#"):
|
|
74
|
+
raise _ParseError("include outside translation-unit prefix")
|
|
75
|
+
self._external()
|
|
76
|
+
if self.used_bases & _STDINT_BASES and "stdint.h" not in self.headers:
|
|
77
|
+
raise _ParseError("fixed-width integer type without stdint.h")
|
|
78
|
+
if "bool" in self.used_bases and "stdbool.h" not in self.headers:
|
|
79
|
+
raise _ParseError("Boolean type or literal without stdbool.h")
|
|
80
|
+
|
|
81
|
+
def _external(self) -> None:
|
|
82
|
+
if self._peek() == "typedef":
|
|
83
|
+
self._record_definition()
|
|
84
|
+
return
|
|
85
|
+
self._storage()
|
|
86
|
+
self._type(allow_void=True)
|
|
87
|
+
self._identifier(file_scope=True)
|
|
88
|
+
if self._accept("("):
|
|
89
|
+
self._parameters()
|
|
90
|
+
self._expect(")")
|
|
91
|
+
if self._accept(";"):
|
|
92
|
+
return
|
|
93
|
+
self._block()
|
|
94
|
+
return
|
|
95
|
+
self._array_suffix()
|
|
96
|
+
if self._accept("="):
|
|
97
|
+
self._initializer()
|
|
98
|
+
self._expect(";")
|
|
99
|
+
|
|
100
|
+
def _record_definition(self) -> None:
|
|
101
|
+
self._expect("typedef")
|
|
102
|
+
self._expect("struct")
|
|
103
|
+
tag = self._identifier(file_scope=True)
|
|
104
|
+
self._expect("{")
|
|
105
|
+
fields: set[str] = set()
|
|
106
|
+
while self._peek() != "}":
|
|
107
|
+
if not self._peek():
|
|
108
|
+
raise _ParseError("unclosed record definition")
|
|
109
|
+
self._type()
|
|
110
|
+
field = self._identifier()
|
|
111
|
+
if field in fields:
|
|
112
|
+
raise _ParseError(f"duplicate record field: {field}")
|
|
113
|
+
fields.add(field)
|
|
114
|
+
self._expect(";")
|
|
115
|
+
if not fields:
|
|
116
|
+
raise _ParseError("empty record definition")
|
|
117
|
+
self._expect("}")
|
|
118
|
+
alias = self._identifier(file_scope=True)
|
|
119
|
+
if alias != tag:
|
|
120
|
+
raise _ParseError("record tag and typedef name must match")
|
|
121
|
+
if alias in self.record_types:
|
|
122
|
+
raise _ParseError(f"duplicate record type: {alias}")
|
|
123
|
+
self.record_types.add(alias)
|
|
124
|
+
self._expect(";")
|
|
125
|
+
|
|
126
|
+
def _parameters(self) -> None:
|
|
127
|
+
if self._peek() == ")":
|
|
128
|
+
raise _ParseError("empty C parameter list must be written as void")
|
|
129
|
+
if self._peek() == "void" and self._peek(1) == ")":
|
|
130
|
+
self.position += 1
|
|
131
|
+
return
|
|
132
|
+
first = True
|
|
133
|
+
while self._peek() != ")":
|
|
134
|
+
if not first:
|
|
135
|
+
self._expect(",")
|
|
136
|
+
self._type()
|
|
137
|
+
self._identifier()
|
|
138
|
+
first = False
|
|
139
|
+
|
|
140
|
+
def _block(self) -> None:
|
|
141
|
+
self._expect("{")
|
|
142
|
+
while self._peek() != "}":
|
|
143
|
+
if not self._peek():
|
|
144
|
+
raise _ParseError("unclosed block")
|
|
145
|
+
self._statement()
|
|
146
|
+
self._expect("}")
|
|
147
|
+
|
|
148
|
+
def _statement(self) -> None:
|
|
149
|
+
token = self._peek()
|
|
150
|
+
if token == "return":
|
|
151
|
+
self.position += 1
|
|
152
|
+
if self._peek() != ";": self._expression()
|
|
153
|
+
self._expect(";")
|
|
154
|
+
return
|
|
155
|
+
if token in {"break", "continue"}:
|
|
156
|
+
self.position += 1; self._expect(";"); return
|
|
157
|
+
if token == "if":
|
|
158
|
+
self.position += 1; self._expect("("); self._expression(); self._expect(")"); self._block()
|
|
159
|
+
if self._accept("else"): self._block()
|
|
160
|
+
return
|
|
161
|
+
if token == "while":
|
|
162
|
+
self.position += 1; self._expect("("); self._expression(); self._expect(")"); self._block(); return
|
|
163
|
+
if token == "for":
|
|
164
|
+
self.position += 1; self._expect("(")
|
|
165
|
+
self._storage(); self._type(); self._identifier(); self._expect("="); self._expression(); self._expect(";")
|
|
166
|
+
self._expression(); self._expect(";")
|
|
167
|
+
self._expression(); self._expect("="); self._expression(); self._expect(")"); self._block(); return
|
|
168
|
+
if self._declaration_start():
|
|
169
|
+
self._storage(); self._type(); self._identifier(); self._array_suffix()
|
|
170
|
+
if self._accept("="): self._initializer()
|
|
171
|
+
self._expect(";")
|
|
172
|
+
return
|
|
173
|
+
self._expression()
|
|
174
|
+
if self._accept("="): self._expression()
|
|
175
|
+
self._expect(";")
|
|
176
|
+
|
|
177
|
+
def _expression(self, minimum: int = 1) -> None:
|
|
178
|
+
self._unary()
|
|
179
|
+
while self._peek() in _BINARY_PRECEDENCE and _BINARY_PRECEDENCE[self._peek()] >= minimum:
|
|
180
|
+
precedence = _BINARY_PRECEDENCE[self._peek()]
|
|
181
|
+
self.position += 1
|
|
182
|
+
self._expression(precedence + 1)
|
|
183
|
+
|
|
184
|
+
def _unary(self) -> None:
|
|
185
|
+
if self._peek() in {"-", "+", "!", "~", "&", "*"}:
|
|
186
|
+
self.position += 1; self._unary(); return
|
|
187
|
+
self._primary()
|
|
188
|
+
|
|
189
|
+
def _primary(self) -> None:
|
|
190
|
+
token = self._peek()
|
|
191
|
+
if token == "(":
|
|
192
|
+
self.position += 1; self._expression(); self._expect(")")
|
|
193
|
+
elif token.startswith('"') or token in {"true", "false"} or re.fullmatch(r"(?:[0-9].*|\.[0-9].*)", token):
|
|
194
|
+
if token in {"true", "false"}: self.used_bases.add("bool")
|
|
195
|
+
self.position += 1
|
|
196
|
+
elif re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", token):
|
|
197
|
+
self.position += 1
|
|
198
|
+
else:
|
|
199
|
+
raise _ParseError(f"expected expression, found {token or 'end of input'}")
|
|
200
|
+
while True:
|
|
201
|
+
if self._accept("("):
|
|
202
|
+
if self._peek() != ")":
|
|
203
|
+
self._expression()
|
|
204
|
+
while self._accept(","): self._expression()
|
|
205
|
+
self._expect(")")
|
|
206
|
+
elif self._accept("["):
|
|
207
|
+
self._expression(); self._expect("]")
|
|
208
|
+
elif self._accept(".") or self._accept("->"):
|
|
209
|
+
self._identifier()
|
|
210
|
+
else:
|
|
211
|
+
break
|
|
212
|
+
|
|
213
|
+
def _initializer(self) -> None:
|
|
214
|
+
if not self._accept("{"):
|
|
215
|
+
self._expression()
|
|
216
|
+
return
|
|
217
|
+
if self._peek() == "}":
|
|
218
|
+
raise _ParseError("empty initializer list")
|
|
219
|
+
self._expression()
|
|
220
|
+
while self._accept(","):
|
|
221
|
+
self._expression()
|
|
222
|
+
self._expect("}")
|
|
223
|
+
|
|
224
|
+
def _array_suffix(self) -> None:
|
|
225
|
+
while self._accept("["):
|
|
226
|
+
token = self._peek()
|
|
227
|
+
if not re.fullmatch(r"(?:0|[1-9][0-9]*)", token):
|
|
228
|
+
raise _ParseError("array extent must be an unsuffixed decimal integer")
|
|
229
|
+
self.position += 1
|
|
230
|
+
self._expect("]")
|
|
231
|
+
|
|
232
|
+
def _type(self, *, allow_void: bool = False) -> None:
|
|
233
|
+
while self._peek() in _QUALIFIERS: self.position += 1
|
|
234
|
+
base = self._peek()
|
|
235
|
+
if base not in _BASE_TYPES | self.record_types or (base == "void" and not allow_void):
|
|
236
|
+
raise _ParseError(f"expected C type, found {base or 'end of input'}")
|
|
237
|
+
self.used_bases.add(base)
|
|
238
|
+
self.position += 1
|
|
239
|
+
while self._accept("*"):
|
|
240
|
+
while self._peek() in _QUALIFIERS:
|
|
241
|
+
self.position += 1
|
|
242
|
+
|
|
243
|
+
def _storage(self) -> None:
|
|
244
|
+
if self._peek() in _STORAGE: self.position += 1
|
|
245
|
+
|
|
246
|
+
def _identifier(self, *, file_scope: bool = False) -> str:
|
|
247
|
+
token = self._peek()
|
|
248
|
+
reserved = _C_KEYWORDS | _TARGET_RESERVED_NAMES | _QUALIFIERS | _STORAGE
|
|
249
|
+
if file_scope:
|
|
250
|
+
reserved |= _C11_EXTERNAL_IDENTIFIERS
|
|
251
|
+
if not re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", token) or token.startswith("_") or token in reserved:
|
|
252
|
+
raise _ParseError(f"expected identifier, found {token or 'end of input'}")
|
|
253
|
+
self.position += 1
|
|
254
|
+
return token
|
|
255
|
+
|
|
256
|
+
def _declaration_start(self) -> bool:
|
|
257
|
+
index = self.position
|
|
258
|
+
if self.tokens[index:index+1] and self.tokens[index] in _STORAGE: index += 1
|
|
259
|
+
while index < len(self.tokens) and self.tokens[index] in _QUALIFIERS: index += 1
|
|
260
|
+
return (
|
|
261
|
+
index < len(self.tokens)
|
|
262
|
+
and self.tokens[index] in _BASE_TYPES | self.record_types
|
|
263
|
+
and self.tokens[index] != "void"
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
def _peek(self, offset: int = 0) -> str:
|
|
267
|
+
index = self.position + offset
|
|
268
|
+
return self.tokens[index] if index < len(self.tokens) else ""
|
|
269
|
+
|
|
270
|
+
def _accept(self, token: str) -> bool:
|
|
271
|
+
if self._peek() == token:
|
|
272
|
+
self.position += 1
|
|
273
|
+
return True
|
|
274
|
+
return False
|
|
275
|
+
|
|
276
|
+
def _expect(self, token: str) -> None:
|
|
277
|
+
if not self._accept(token):
|
|
278
|
+
raise _ParseError(f"expected {token}, found {self._peek() or 'end of input'}")
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def validate_c_text(text: str) -> CTextConformanceResult:
|
|
282
|
+
if text and not text.endswith("\n"):
|
|
283
|
+
return CTextConformanceResult(False, "missing final newline", 0)
|
|
284
|
+
position = 0
|
|
285
|
+
tokens: list[str] = []
|
|
286
|
+
while position < len(text):
|
|
287
|
+
match = _TOKEN.match(text, position)
|
|
288
|
+
if not match:
|
|
289
|
+
return CTextConformanceResult(False, f"unexpected character at byte {len(text[:position].encode('utf-8'))}", len(tokens))
|
|
290
|
+
position = match.end()
|
|
291
|
+
if match.lastgroup != "space":
|
|
292
|
+
tokens.append(match.group(0))
|
|
293
|
+
try:
|
|
294
|
+
_Parser(tuple(tokens)).parse()
|
|
295
|
+
except _ParseError as exc:
|
|
296
|
+
return CTextConformanceResult(False, str(exc), len(tokens))
|
|
297
|
+
return CTextConformanceResult(True, "accepted", len(tokens))
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from pycforge.converter.ir.c_ir.model import *
|
|
4
|
+
from pycforge.converter.ir.c_ir.validation import validate_translation_unit
|
|
5
|
+
|
|
6
|
+
_PRECEDENCE={CBinaryOp.LOGICAL_OR:3,CBinaryOp.LOGICAL_AND:4,CBinaryOp.BIT_OR:5,CBinaryOp.BIT_XOR:6,CBinaryOp.BIT_AND:7,CBinaryOp.EQUAL:8,CBinaryOp.NOT_EQUAL:8,CBinaryOp.LESS:9,CBinaryOp.LESS_EQUAL:9,CBinaryOp.GREATER:9,CBinaryOp.GREATER_EQUAL:9,CBinaryOp.SHIFT_LEFT:10,CBinaryOp.SHIFT_RIGHT:10,CBinaryOp.ADD:11,CBinaryOp.SUBTRACT:11,CBinaryOp.MULTIPLY:12,CBinaryOp.DIVIDE:12,CBinaryOp.REMAINDER:12}
|
|
7
|
+
@dataclass(frozen=True,slots=True)
|
|
8
|
+
class SourceOutputMapping:
|
|
9
|
+
c_node_id:str; origin_kind:str; source_document_id:str|None; source_node_ids:tuple[str,...]; rule_plan_id:str|None; start_byte:int; end_byte:int; start_line:int; start_column:int; end_line:int; end_column:int
|
|
10
|
+
@dataclass(frozen=True,slots=True)
|
|
11
|
+
class RenderedC:
|
|
12
|
+
text:str; mappings:tuple[SourceOutputMapping,...]
|
|
13
|
+
|
|
14
|
+
class CRenderer:
|
|
15
|
+
def __init__(self)->None:self._parts=[];self._maps=[];self._line=1;self._column=0;self._byte=0
|
|
16
|
+
def _render_external(self,d:CExternalDeclaration)->None:
|
|
17
|
+
self._mapped(d.node_id,d.provenance,lambda:self._render_external_inner(d))
|
|
18
|
+
def _render_external_inner(self,d):
|
|
19
|
+
if isinstance(d,CRecordDefinition):
|
|
20
|
+
self._render_record_definition(d)
|
|
21
|
+
elif isinstance(d,CFunctionPrototype):
|
|
22
|
+
self._render_function_signature(d); self._write(";\n")
|
|
23
|
+
elif isinstance(d,CFunctionDefinition):
|
|
24
|
+
self._render_function_signature(d); self._write("\n"); self._render_block(d.body)
|
|
25
|
+
elif isinstance(d,CVariableDeclaration):self._render_var(d,0)
|
|
26
|
+
else:raise TypeError(type(d).__name__)
|
|
27
|
+
def _render_record_definition(self,d:CRecordDefinition)->None:
|
|
28
|
+
self._write("typedef struct "+d.identifier.spelling+" {\n")
|
|
29
|
+
for field in d.fields:
|
|
30
|
+
self._mapped(
|
|
31
|
+
field.node_id,
|
|
32
|
+
field.provenance,
|
|
33
|
+
lambda field=field:self._write(
|
|
34
|
+
" "+self._declarator(field.type_ref,field.identifier.spelling)+";\n"
|
|
35
|
+
),
|
|
36
|
+
)
|
|
37
|
+
self._write("} "+d.identifier.spelling+";\n")
|
|
38
|
+
def _render_function_signature(self,d):
|
|
39
|
+
prefix="" if d.storage is CStorage.NONE else d.storage.value+" "
|
|
40
|
+
self._write(prefix+self._type(d.return_type)+" "+d.identifier.spelling+"(")
|
|
41
|
+
if not d.parameters:self._write("void")
|
|
42
|
+
for index,p in enumerate(d.parameters):
|
|
43
|
+
if index:self._write(", ")
|
|
44
|
+
self._mapped(p.node_id,p.provenance,lambda p=p:self._write(self._declarator(p.type_ref,p.identifier.spelling)))
|
|
45
|
+
self._write(")")
|
|
46
|
+
def _render_block(self,b:CBlock)->None:
|
|
47
|
+
self._mapped(b.node_id,b.provenance,lambda:self._render_block_inner(b))
|
|
48
|
+
def _render_block_inner(self,b):
|
|
49
|
+
self._write("{\n")
|
|
50
|
+
for s in b.statements:self._render_statement(s,1)
|
|
51
|
+
self._write("}\n")
|
|
52
|
+
def _render_statement(self,s:CStatement,indent:int)->None:
|
|
53
|
+
def inner():
|
|
54
|
+
self._write(" "*indent)
|
|
55
|
+
if isinstance(s,CVariableDeclaration):self._render_var(s,indent,leading=False)
|
|
56
|
+
elif isinstance(s,CExpressionStatement):
|
|
57
|
+
self._render_expr(s.expression); self._write(";\n")
|
|
58
|
+
elif isinstance(s,CReturnStatement):
|
|
59
|
+
self._write("return")
|
|
60
|
+
if s.expression is not None:
|
|
61
|
+
self._write(" "); self._render_expr(s.expression)
|
|
62
|
+
self._write(";\n")
|
|
63
|
+
elif isinstance(s,CAssignmentStatement):
|
|
64
|
+
self._render_expr(s.target); self._write(" = "); self._render_expr(s.value); self._write(";\n")
|
|
65
|
+
elif isinstance(s,CIfStatement):
|
|
66
|
+
self._write("if ("); self._render_expr(s.condition); self._write(")\n"); self._render_block_at(s.then_block,indent)
|
|
67
|
+
if s.else_block is not None:
|
|
68
|
+
self._write(" "*indent+"else\n"); self._render_block_at(s.else_block,indent)
|
|
69
|
+
elif isinstance(s,CWhileStatement):
|
|
70
|
+
self._write("while ("); self._render_expr(s.condition); self._write(")\n"); self._render_block_at(s.body,indent)
|
|
71
|
+
elif isinstance(s,CForStatement):
|
|
72
|
+
d=s.initializer
|
|
73
|
+
self._write("for (")
|
|
74
|
+
self._mapped(d.node_id,d.provenance,lambda:self._render_for_initializer(d))
|
|
75
|
+
self._write("; ")
|
|
76
|
+
self._render_expr(s.condition); self._write("; ")
|
|
77
|
+
self._mapped(s.update.node_id,s.update.provenance,lambda:self._render_assignment_fragment(s.update))
|
|
78
|
+
self._write(")\n")
|
|
79
|
+
self._render_block_at(s.body,indent)
|
|
80
|
+
elif isinstance(s,CBreakStatement): self._write("break;\n")
|
|
81
|
+
elif isinstance(s,CContinueStatement): self._write("continue;\n")
|
|
82
|
+
else:raise TypeError(type(s).__name__)
|
|
83
|
+
self._mapped(s.node_id,s.provenance,inner)
|
|
84
|
+
def _render_block_at(self,b:CBlock,indent:int)->None:
|
|
85
|
+
self._mapped(b.node_id,b.provenance,lambda:self._render_block_at_inner(b,indent))
|
|
86
|
+
def _render_block_at_inner(self,b,indent):
|
|
87
|
+
self._write(" "*indent+"{\n")
|
|
88
|
+
for st in b.statements:self._render_statement(st,indent+1)
|
|
89
|
+
self._write(" "*indent+"}\n")
|
|
90
|
+
def _render_var(self,d,indent,leading=True):
|
|
91
|
+
prefix="" if d.storage is CStorage.NONE else d.storage.value+" "
|
|
92
|
+
self._write(prefix+self._declarator(d.type_ref,d.identifier.spelling))
|
|
93
|
+
if d.initializer is not None:
|
|
94
|
+
self._write(" = "); self._render_expr(d.initializer)
|
|
95
|
+
self._write(";\n")
|
|
96
|
+
def _render_for_initializer(self,d:CVariableDeclaration)->None:
|
|
97
|
+
self._write(self._declarator(d.type_ref,d.identifier.spelling)+" = ")
|
|
98
|
+
self._render_expr(d.initializer)
|
|
99
|
+
def _render_assignment_fragment(self,s:CAssignmentStatement)->None:
|
|
100
|
+
self._render_expr(s.target); self._write(" = "); self._render_expr(s.value)
|
|
101
|
+
def _type(self,t:CType)->str:
|
|
102
|
+
q=" ".join(x.value for x in t.qualifiers)
|
|
103
|
+
base=(q+" " if q else "")+t.base
|
|
104
|
+
return base+(" " + "*"*t.pointer_depth if t.pointer_depth else "")
|
|
105
|
+
def _declarator(self,t:CType,name:str)->str:
|
|
106
|
+
suffix="".join(f"[{extent}]" for extent in t.array_extents)
|
|
107
|
+
rendered_type=self._type(t)
|
|
108
|
+
if t.object_const:
|
|
109
|
+
if t.pointer_depth:
|
|
110
|
+
return rendered_type+" const "+name+suffix
|
|
111
|
+
return "const "+rendered_type+" "+name+suffix
|
|
112
|
+
return rendered_type+" "+name+suffix
|
|
113
|
+
def _precedence(self,e:CExpression)->int:
|
|
114
|
+
if isinstance(e,(CIntegerLiteral,CFloatLiteral,CBooleanLiteral,CStringLiteral,CIdentifierRef,CInitializerList,CRecordInitializer)): return 15
|
|
115
|
+
if isinstance(e,(CCallExpr,CSubscriptExpr,CMemberAccessExpr)): return 14
|
|
116
|
+
if isinstance(e,CUnaryExpr): return 13
|
|
117
|
+
if isinstance(e,CBinaryExpr): return _PRECEDENCE[e.op]
|
|
118
|
+
raise TypeError(type(e).__name__)
|
|
119
|
+
def _render_expr(self,e:CExpression,parent:int=0,right_child:bool=False)->None:
|
|
120
|
+
prec=self._precedence(e)
|
|
121
|
+
paren=prec<parent or (right_child and prec==parent and isinstance(e,CBinaryExpr))
|
|
122
|
+
def inner():
|
|
123
|
+
if paren:self._write("(")
|
|
124
|
+
if isinstance(e,CIntegerLiteral):self._write(str(e.value)+e.suffix)
|
|
125
|
+
elif isinstance(e,CFloatLiteral):self._write(repr(e.value))
|
|
126
|
+
elif isinstance(e,CBooleanLiteral):self._write("true" if e.value else "false")
|
|
127
|
+
elif isinstance(e,CStringLiteral):self._write('"'+self._escape_string(e.value)+'"')
|
|
128
|
+
elif isinstance(e,CIdentifierRef):self._write(self._binding_spelling(e.binding_id))
|
|
129
|
+
elif isinstance(e,(CInitializerList,CRecordInitializer)):
|
|
130
|
+
self._write("{")
|
|
131
|
+
for i,item in enumerate(e.elements):
|
|
132
|
+
if i:self._write(", ")
|
|
133
|
+
self._render_expr(item)
|
|
134
|
+
self._write("}")
|
|
135
|
+
elif isinstance(e,CCallExpr):
|
|
136
|
+
self._render_expr(e.callee,14);self._write("(")
|
|
137
|
+
for i,a in enumerate(e.arguments):
|
|
138
|
+
if i:self._write(", ")
|
|
139
|
+
self._render_expr(a)
|
|
140
|
+
self._write(")")
|
|
141
|
+
elif isinstance(e,CSubscriptExpr):
|
|
142
|
+
self._render_expr(e.container,14);self._write("[");self._render_expr(e.index);self._write("]")
|
|
143
|
+
elif isinstance(e,CMemberAccessExpr):
|
|
144
|
+
self._render_expr(e.receiver,14)
|
|
145
|
+
self._write("." if e.mode is CMemberAccessMode.DIRECT else "->")
|
|
146
|
+
self._write(self._binding_spelling(e.field_binding_id))
|
|
147
|
+
elif isinstance(e,CUnaryExpr):
|
|
148
|
+
# Parenthesize a nested unary expression so two adjacent '-'
|
|
149
|
+
# tokens cannot be re-lexed by C as pre-decrement.
|
|
150
|
+
self._write(e.op.value);self._render_expr(e.operand,prec+1)
|
|
151
|
+
elif isinstance(e,CBinaryExpr):
|
|
152
|
+
self._render_expr(e.left,prec);self._write(f" {e.op.value} ");self._render_expr(e.right,prec,True)
|
|
153
|
+
else:raise TypeError(type(e).__name__)
|
|
154
|
+
if paren:self._write(")")
|
|
155
|
+
self._mapped(e.node_id,e.provenance,inner)
|
|
156
|
+
@staticmethod
|
|
157
|
+
def _escape_string(value:str)->str:
|
|
158
|
+
out=[]
|
|
159
|
+
for index,ch in enumerate(value):
|
|
160
|
+
code=ord(ch)
|
|
161
|
+
if ch=='\\': out.append('\\\\')
|
|
162
|
+
elif ch=='"': out.append('\\"')
|
|
163
|
+
# C11 performs trigraph replacement before tokenization. Escaping
|
|
164
|
+
# every question mark prevents text such as ??/ from becoming a
|
|
165
|
+
# backslash during translation phase 1.
|
|
166
|
+
elif ch=='?': out.append('\\?')
|
|
167
|
+
elif ch=='\n': out.append('\\n')
|
|
168
|
+
elif ch=='\r': out.append('\\r')
|
|
169
|
+
elif ch=='\t': out.append('\\t')
|
|
170
|
+
elif 32 <= code < 127: out.append(ch)
|
|
171
|
+
else:
|
|
172
|
+
encoded=ch.encode('utf-8')
|
|
173
|
+
next_is_hex=index+1<len(value) and value[index+1] in '0123456789abcdefABCDEF'
|
|
174
|
+
for byte_index,b in enumerate(encoded):
|
|
175
|
+
# C hexadecimal escapes consume an unbounded run of hex
|
|
176
|
+
# digits. Use a fixed-width octal escape for the final
|
|
177
|
+
# byte when the following source character is hexadecimal.
|
|
178
|
+
out.append(f"\\{b:03o}" if next_is_hex and byte_index+1==len(encoded) else f"\\x{b:02x}")
|
|
179
|
+
return ''.join(out)
|
|
180
|
+
def _binding_spelling(self,binding_id:str)->str:
|
|
181
|
+
# populated from validated declarations before expression rendering
|
|
182
|
+
return self._bindings[binding_id]
|
|
183
|
+
def _mapped(self,node_id,prov,fn):
|
|
184
|
+
start=(self._byte,self._line,self._column);fn();end=(self._byte,self._line,self._column)
|
|
185
|
+
self._maps.append(SourceOutputMapping(node_id,prov.origin_kind,prov.source_document_id,prov.source_node_ids,prov.rule_plan_id,start[0],end[0],start[1],start[2],end[1],end[2]))
|
|
186
|
+
def _write(self,text:str)->None:
|
|
187
|
+
self._parts.append(text);self._byte+=len(text.encode("utf-8"))
|
|
188
|
+
lines=text.split("\n")
|
|
189
|
+
if len(lines)>1:self._line+=len(lines)-1;self._column=len(lines[-1])
|
|
190
|
+
else:self._column+=len(text)
|
|
191
|
+
def render(self,unit:CTranslationUnit)->RenderedC:
|
|
192
|
+
valid=validate_translation_unit(unit)
|
|
193
|
+
if not valid.accepted:raise ValueError("invalid C IR: "+"; ".join(valid.errors))
|
|
194
|
+
self._bindings={}
|
|
195
|
+
for d in unit.declarations:
|
|
196
|
+
if isinstance(d,CRecordDefinition):
|
|
197
|
+
for field in d.fields:
|
|
198
|
+
self._bindings[field.identifier.binding_id]=field.identifier.spelling
|
|
199
|
+
elif isinstance(d,(CFunctionPrototype,CFunctionDefinition)):
|
|
200
|
+
self._bindings[d.identifier.binding_id]=d.identifier.spelling
|
|
201
|
+
for p in d.parameters:self._bindings[p.identifier.binding_id]=p.identifier.spelling
|
|
202
|
+
def collect(st):
|
|
203
|
+
if isinstance(st,CVariableDeclaration): self._bindings[st.identifier.binding_id]=st.identifier.spelling
|
|
204
|
+
elif isinstance(st,CIfStatement):
|
|
205
|
+
for x in st.then_block.statements: collect(x)
|
|
206
|
+
if st.else_block:
|
|
207
|
+
for x in st.else_block.statements: collect(x)
|
|
208
|
+
elif isinstance(st,(CWhileStatement,CForStatement)):
|
|
209
|
+
if isinstance(st,CForStatement): self._bindings[st.initializer.identifier.binding_id]=st.initializer.identifier.spelling
|
|
210
|
+
for x in st.body.statements: collect(x)
|
|
211
|
+
if isinstance(d,CFunctionDefinition):
|
|
212
|
+
for st in d.body.statements: collect(st)
|
|
213
|
+
elif isinstance(d,CVariableDeclaration):self._bindings[d.identifier.binding_id]=d.identifier.spelling
|
|
214
|
+
self._parts=[];self._maps=[];self._line=1;self._column=0;self._byte=0
|
|
215
|
+
for inc in unit.includes:self._mapped(inc.node_id,inc.provenance,lambda inc=inc:self._write(f"#include <{inc.header}>\n" if inc.system else f'#include "{inc.header}"\n'))
|
|
216
|
+
if unit.includes and unit.declarations:self._write("\n")
|
|
217
|
+
for index,decl in enumerate(unit.declarations):
|
|
218
|
+
self._render_external(decl)
|
|
219
|
+
if index+1<len(unit.declarations):self._write("\n")
|
|
220
|
+
return RenderedC("".join(self._parts),tuple(self._maps))
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Phase 14B conditional temporary-region analysis and lowering."""
|
|
2
|
+
|
|
3
|
+
from .analysis import ConditionalRegionAnalyzer
|
|
4
|
+
from .model import (
|
|
5
|
+
CONDITIONAL_REGION_KEY_DOMAIN,
|
|
6
|
+
CONDITIONAL_REGION_LOWERING_SHAPE,
|
|
7
|
+
CONDITIONAL_REGION_OBLIGATIONS,
|
|
8
|
+
CONDITIONAL_REGION_PROVENANCE_EVIDENCE,
|
|
9
|
+
CONDITIONAL_REGION_TABLE_DEPENDENCIES,
|
|
10
|
+
CONDITIONAL_REGION_TABLE_ID,
|
|
11
|
+
ConditionalEvaluationMode,
|
|
12
|
+
ConditionalGuardPolarity,
|
|
13
|
+
ConditionalOperandPlacementFact,
|
|
14
|
+
ConditionalRegionAnalysis,
|
|
15
|
+
ConditionalRegionAnalysisCanceled,
|
|
16
|
+
ConditionalRegionAnalysisError,
|
|
17
|
+
ConditionalRegionFact,
|
|
18
|
+
ConditionalRegionKind,
|
|
19
|
+
ConditionalRegionValidationCanceled,
|
|
20
|
+
conditional_region_id,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
# validation is imported last so its independent reconstruction cannot become
|
|
24
|
+
# an accidental dependency of the producer or lowerer.
|
|
25
|
+
from .validation import validate_conditional_region_facts
|
|
26
|
+
|
|
27
|
+
_LOWERING_EXPORTS = {
|
|
28
|
+
"ConditionalRegionCIRLowerer",
|
|
29
|
+
"ConditionalRegionLoweringServices",
|
|
30
|
+
"bind_conditional_region_lowerer",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def __getattr__(name: str):
|
|
35
|
+
"""Load the C-IR-facing half only when a lowering symbol is requested.
|
|
36
|
+
|
|
37
|
+
Importing conditional analysis or validation must not acquire C IR through
|
|
38
|
+
package initialization.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
if name not in _LOWERING_EXPORTS:
|
|
42
|
+
raise AttributeError(name)
|
|
43
|
+
from . import lowering
|
|
44
|
+
|
|
45
|
+
value = getattr(lowering, name)
|
|
46
|
+
globals()[name] = value
|
|
47
|
+
return value
|
|
48
|
+
|
|
49
|
+
__all__ = [
|
|
50
|
+
"CONDITIONAL_REGION_KEY_DOMAIN",
|
|
51
|
+
"CONDITIONAL_REGION_LOWERING_SHAPE",
|
|
52
|
+
"CONDITIONAL_REGION_OBLIGATIONS",
|
|
53
|
+
"CONDITIONAL_REGION_PROVENANCE_EVIDENCE",
|
|
54
|
+
"CONDITIONAL_REGION_TABLE_DEPENDENCIES",
|
|
55
|
+
"CONDITIONAL_REGION_TABLE_ID",
|
|
56
|
+
"ConditionalEvaluationMode",
|
|
57
|
+
"ConditionalGuardPolarity",
|
|
58
|
+
"ConditionalOperandPlacementFact",
|
|
59
|
+
"ConditionalRegionAnalysis",
|
|
60
|
+
"ConditionalRegionAnalysisCanceled",
|
|
61
|
+
"ConditionalRegionAnalysisError",
|
|
62
|
+
"ConditionalRegionValidationCanceled",
|
|
63
|
+
"ConditionalRegionCIRLowerer",
|
|
64
|
+
"ConditionalRegionFact",
|
|
65
|
+
"ConditionalRegionKind",
|
|
66
|
+
"ConditionalRegionLoweringServices",
|
|
67
|
+
"ConditionalRegionAnalyzer",
|
|
68
|
+
"bind_conditional_region_lowerer",
|
|
69
|
+
"conditional_region_id",
|
|
70
|
+
"validate_conditional_region_facts",
|
|
71
|
+
]
|