onec-interactive-runtime-core 0.1.19__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 (87) hide show
  1. onec_interactive_runtime_core-0.1.19.dist-info/METADATA +12 -0
  2. onec_interactive_runtime_core-0.1.19.dist-info/RECORD +87 -0
  3. onec_interactive_runtime_core-0.1.19.dist-info/WHEEL +4 -0
  4. onec_interactive_runtime_core-0.1.19.dist-info/licenses/COPYRIGHT +9 -0
  5. onec_interactive_runtime_core-0.1.19.dist-info/licenses/LICENSE +232 -0
  6. onec_interactive_runtime_core-0.1.19.dist-info/licenses/THIRD_PARTY_NOTICES.txt +32 -0
  7. onec_runtime/AGENTS.md +7 -0
  8. onec_runtime/__init__.py +3 -0
  9. onec_runtime/artifacts.py +59 -0
  10. onec_runtime/bootstrap.py +310 -0
  11. onec_runtime/breakpoint_workspace.py +249 -0
  12. onec_runtime/bsl/__init__.py +139 -0
  13. onec_runtime/bsl/diagnostics.py +1046 -0
  14. onec_runtime/bsl/full_ast_worker_projection.py +522 -0
  15. onec_runtime/bsl/generated_semantic_parser.py +6322 -0
  16. onec_runtime/bsl/lexer.py +164 -0
  17. onec_runtime/bsl/module_catalog.py +420 -0
  18. onec_runtime/bsl/module_delta.py +1079 -0
  19. onec_runtime/bsl/module_universe.py +1877 -0
  20. onec_runtime/bsl/notebook_cells.py +232 -0
  21. onec_runtime/bsl/notebook_method_globals.py +74 -0
  22. onec_runtime/bsl/notebook_methods.py +175 -0
  23. onec_runtime/bsl/parser_artifact_identity.py +119 -0
  24. onec_runtime/bsl/parser_target.py +388 -0
  25. onec_runtime/bsl/preprocessor.py +16 -0
  26. onec_runtime/bsl/semantic_lowering.py +1539 -0
  27. onec_runtime/bsl/source_maps.py +2411 -0
  28. onec_runtime/bsl/worker_dependency_resolver.py +289 -0
  29. onec_runtime/bsl/worker_preprocessor.py +247 -0
  30. onec_runtime/bsl/worker_projection_model.py +137 -0
  31. onec_runtime/bsl/worker_reload_source_map.py +1697 -0
  32. onec_runtime/capture.py +113 -0
  33. onec_runtime/capture_source.py +453 -0
  34. onec_runtime/compact_table.py +376 -0
  35. onec_runtime/compact_table_backend.py +500 -0
  36. onec_runtime/config.py +198 -0
  37. onec_runtime/configurator_agent.py +520 -0
  38. onec_runtime/controller_worker.py +400 -0
  39. onec_runtime/credentials.py +18 -0
  40. onec_runtime/epf_container.py +196 -0
  41. onec_runtime/errors.py +205 -0
  42. onec_runtime/experiment.py +130 -0
  43. onec_runtime/extension_bundle.py +944 -0
  44. onec_runtime/extension_lifecycle.py +402 -0
  45. onec_runtime/extension_state.py +222 -0
  46. onec_runtime/fault_injection.py +30 -0
  47. onec_runtime/kernel.py +179 -0
  48. onec_runtime/lease.py +123 -0
  49. onec_runtime/observation.py +287 -0
  50. onec_runtime/performance_profile.py +245 -0
  51. onec_runtime/privacy.py +263 -0
  52. onec_runtime/processes.py +265 -0
  53. onec_runtime/prototype_runtime.py +2644 -0
  54. onec_runtime/rdbg/__init__.py +1 -0
  55. onec_runtime/rdbg/models.py +130 -0
  56. onec_runtime/rdbg/reconnect.py +59 -0
  57. onec_runtime/rdbg/session.py +913 -0
  58. onec_runtime/rdbg/transport.py +138 -0
  59. onec_runtime/rdbg/xml_codec.py +980 -0
  60. onec_runtime/recovery.py +106 -0
  61. onec_runtime/recovery_journal.py +79 -0
  62. onec_runtime/resources/extension/OnecInteractiveRuntime.cfe +0 -0
  63. onec_runtime/resources/extension/extension-manifest.json +108 -0
  64. onec_runtime/runtime_api.py +5272 -0
  65. onec_runtime/runtime_contracts.py +196 -0
  66. onec_runtime/server_worker.py +2034 -0
  67. onec_runtime/session.py +2123 -0
  68. onec_runtime/startup_diagnostics.py +45 -0
  69. onec_runtime/stop_routing.py +65 -0
  70. onec_runtime/supervised_processes.py +232 -0
  71. onec_runtime/supervised_runtime.py +512 -0
  72. onec_runtime/supervisor.py +363 -0
  73. onec_runtime/supervisor_model.py +148 -0
  74. onec_runtime/supervisor_protocol.py +77 -0
  75. onec_runtime/table_materialization.py +471 -0
  76. onec_runtime/table_transfer_backend.py +203 -0
  77. onec_runtime/table_value.py +311 -0
  78. onec_runtime/toolchain.py +730 -0
  79. onec_runtime/value_materialization.py +432 -0
  80. onec_runtime/value_transfer_backend.py +199 -0
  81. onec_runtime/worker_breakpoints.py +1431 -0
  82. onec_runtime/worker_epf.py +313 -0
  83. onec_runtime/worker_epf_template.py +53 -0
  84. onec_runtime/worker_stage_protocol.py +516 -0
  85. onec_runtime/worker_universe.py +3772 -0
  86. onec_runtime_build/__init__.py +1 -0
  87. onec_runtime_build/parser_target_development.py +116 -0
@@ -0,0 +1,388 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Sequence
4
+ from dataclasses import dataclass
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from onec_runtime.bsl.parser_artifact_identity import (
9
+ ParserArtifactManifest,
10
+ verify_parser_artifact_manifest,
11
+ )
12
+ from onec_runtime.bsl.lexer import Token, tokenize
13
+ from onec_runtime.bsl.source_maps import SourceSpan
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class ParseNode:
18
+ production: str
19
+ alternative: int
20
+ children: tuple["ParseNode | Token", ...]
21
+
22
+
23
+ class BslParseError(ValueError):
24
+ def __init__(
25
+ self,
26
+ message: str,
27
+ *,
28
+ span: SourceSpan = SourceSpan(0, 0),
29
+ code: str = "parse_error",
30
+ ) -> None:
31
+ super().__init__(message)
32
+ self.span = span
33
+ self.code = code
34
+
35
+
36
+ @dataclass(frozen=True, slots=True)
37
+ class GeneratedParserMetadata:
38
+ """Provenance retained by the installed generated parser artifact."""
39
+
40
+ grammar_sha256: str
41
+ parsergen_package_sha256: str | None
42
+ manifest: ParserArtifactManifest | None = None
43
+
44
+ def __post_init__(self) -> None:
45
+ if (
46
+ self.manifest is not None
47
+ and self.grammar_sha256 != self.manifest.identity_sha256
48
+ ):
49
+ raise ValueError("generated parser metadata identity is inconsistent")
50
+
51
+ @property
52
+ def parser_identity_sha256(self) -> str:
53
+ """Return the complete artifact identity retained for cache admission."""
54
+ return self.grammar_sha256
55
+
56
+
57
+ @dataclass(frozen=True, slots=True)
58
+ class DevelopmentParserDetails:
59
+ """Parsergen-only details available from ``from_files()`` validation."""
60
+
61
+ resolved: Any
62
+ analysis: Any
63
+ parser_ir: Any
64
+ validation_warnings: tuple[dict[str, str], ...]
65
+
66
+
67
+ class PythonParserTarget:
68
+ """Runs the committed semantic parser, or a development validation build."""
69
+
70
+ ENTRYPOINTS = {
71
+ "module": "Модуль",
72
+ "notebook": "БлокНоутбука",
73
+ "notebook_cell": "ЯчейкаНоутбука",
74
+ "expression": "ОтдельноеВыражение",
75
+ "statement": "ОтдельнаяИнструкция",
76
+ "preprocessor": "ДирективаПрепроцессора",
77
+ }
78
+
79
+ def __init__(
80
+ self,
81
+ generated_parser_type: type[Any],
82
+ generated_error: type[Exception],
83
+ metadata: GeneratedParserMetadata,
84
+ *,
85
+ generated_source: str | None = None,
86
+ development: DevelopmentParserDetails | None = None,
87
+ ) -> None:
88
+ self._generated_parser_type = generated_parser_type
89
+ self.generated_parser = generated_parser_type()
90
+ self.generated_error = generated_error
91
+ self.metadata = metadata
92
+ self.generated_source = generated_source
93
+ self.development = development
94
+
95
+ @property
96
+ def grammar_sha256(self) -> str:
97
+ return self.metadata.grammar_sha256
98
+
99
+ @classmethod
100
+ def from_generated(cls) -> "PythonParserTarget":
101
+ """Load packaged code and allocate one mutable parser cursor."""
102
+ from onec_runtime.bsl import generated_semantic_parser
103
+
104
+ manifest = verify_parser_artifact_manifest(
105
+ generated_semantic_parser.PARSER_ARTIFACT_MANIFEST_JSON
106
+ )
107
+ metadata = GeneratedParserMetadata(
108
+ manifest.identity_sha256,
109
+ manifest.parsergen_package_sha256,
110
+ manifest,
111
+ )
112
+ return cls(
113
+ generated_semantic_parser.GeneratedParser,
114
+ generated_semantic_parser.GeneratedParseError,
115
+ metadata,
116
+ )
117
+
118
+ @classmethod
119
+ def from_files(
120
+ cls,
121
+ grammar_path: Path,
122
+ parsergen_src: Path,
123
+ *,
124
+ lookahead: int = 1,
125
+ ) -> "PythonParserTarget":
126
+ """Build through the optional build-time development adapter."""
127
+ from importlib import import_module
128
+
129
+ adapter = import_module("onec_runtime_build.parser_target_development")
130
+ return adapter.build_combined_python_parser_target(
131
+ cls,
132
+ grammar_path,
133
+ parsergen_src,
134
+ lookahead=lookahead,
135
+ )
136
+
137
+ def parse(self, source: str, entrypoint: str) -> None:
138
+ self.parse_ast(source, entrypoint)
139
+
140
+ def new_instance(self) -> "PythonParserTarget":
141
+ """Reuse generated code while keeping parser cursor state controller-local."""
142
+ return PythonParserTarget(
143
+ self._generated_parser_type,
144
+ self.generated_error,
145
+ self.metadata,
146
+ generated_source=self.generated_source,
147
+ development=self.development,
148
+ )
149
+
150
+ def parse_ast(self, source: str, entrypoint: str) -> Any:
151
+ return self.parse_tokens_ast(tokenize(source), entrypoint)
152
+
153
+ def parse_tokens(self, tokens: Sequence[Token], entrypoint: str) -> None:
154
+ self.parse_tokens_ast(tokens, entrypoint)
155
+
156
+ def parse_tokens_ast(
157
+ self,
158
+ tokens: Sequence[Token],
159
+ entrypoint: str,
160
+ ) -> Any:
161
+ entrypoint_name = self._entrypoint_name(entrypoint)
162
+ try:
163
+ return self.generated_parser.parse(tokens, entrypoint_name)
164
+ except self.generated_error as error:
165
+ actual = error.actual
166
+ start = (
167
+ tokens[error.position].start
168
+ if error.position < len(tokens)
169
+ else tokens[-1].end if tokens else 0
170
+ )
171
+ raise BslParseError(
172
+ f"Unexpected {actual!r} at {start}; expected {error.expected!r}",
173
+ span=SourceSpan(start, start),
174
+ code="unexpected_token",
175
+ ) from error
176
+
177
+ def _entrypoint_name(self, entrypoint: str) -> str:
178
+ entrypoint_name = next(
179
+ (
180
+ name
181
+ for name, production in self.ENTRYPOINTS.items()
182
+ if production == entrypoint
183
+ ),
184
+ None,
185
+ )
186
+ if entrypoint_name is None:
187
+ raise ValueError(f"Unknown parser entrypoint production {entrypoint!r}")
188
+ return entrypoint_name
189
+
190
+ def parse_interpreted(self, source: str, entrypoint: str) -> ParseNode:
191
+ return self.parse_tokens_interpreted(tokenize(source), entrypoint)
192
+
193
+ def parse_tokens_interpreted(
194
+ self,
195
+ tokens: Sequence[Token],
196
+ entrypoint: str,
197
+ ) -> ParseNode:
198
+ self._require_development()
199
+ self.tokens = tokens
200
+ self.position = 0
201
+ node = self._production(entrypoint)
202
+ if self.position != len(self.tokens):
203
+ token = self.tokens[self.position]
204
+ raise BslParseError(
205
+ f"Unexpected {token.text!r} at {token.start}",
206
+ span=SourceSpan(token.start, token.start),
207
+ code="unexpected_token",
208
+ )
209
+ return node
210
+
211
+ def recognize_tokens_interpreted(
212
+ self,
213
+ tokens: Sequence[Token],
214
+ entrypoint: str,
215
+ ) -> None:
216
+ self._require_development()
217
+ self.tokens = tokens
218
+ self.position = 0
219
+ self._recognize_production(entrypoint)
220
+ if self.position != len(self.tokens):
221
+ token = self.tokens[self.position]
222
+ raise BslParseError(
223
+ f"Unexpected {token.text!r} at {token.start}",
224
+ span=SourceSpan(token.start, token.start),
225
+ code="unexpected_token",
226
+ )
227
+
228
+ def _lookahead_matches(self, word: tuple[str, ...]) -> bool:
229
+ actual = tuple(token.type for token in self.tokens[self.position : self.position + len(word)])
230
+ if len(actual) < len(word):
231
+ actual += ("$",) * (len(word) - len(actual))
232
+ return actual == word
233
+
234
+ def _production(self, name: str) -> ParseNode:
235
+ development = self._require_development()
236
+ alternatives = development.resolved.productions[name]
237
+ matches = [
238
+ (alternative_number, alternative)
239
+ for alternative_number, alternative in enumerate(alternatives, start=1)
240
+ if any(
241
+ self._lookahead_matches(word)
242
+ for word in development.analysis.select[(name, alternative_number)]
243
+ )
244
+ ]
245
+ if len(matches) != 1:
246
+ lookahead = [
247
+ token.type
248
+ for token in self.tokens[
249
+ self.position : self.position + development.analysis.k
250
+ ]
251
+ ]
252
+ offset = self._current_offset()
253
+ raise BslParseError(
254
+ f"No unique alternative for {name} at {lookahead}",
255
+ span=SourceSpan(offset, offset),
256
+ code="ambiguous_alternative",
257
+ )
258
+ alternative_number, alternative = matches[0]
259
+ children: list[ParseNode | Token] = []
260
+ for symbol in alternative.symbols:
261
+ if hasattr(symbol, "token_types"):
262
+ if self.position >= len(self.tokens):
263
+ offset = self._current_offset()
264
+ raise BslParseError(
265
+ f"Unexpected end while parsing {name}",
266
+ span=SourceSpan(offset, offset),
267
+ code="unexpected_end",
268
+ )
269
+ token = self.tokens[self.position]
270
+ if token.type not in symbol.token_types:
271
+ raise BslParseError(
272
+ f"Expected {sorted(symbol.token_types)}, got {token.type} at {token.start}",
273
+ span=SourceSpan(token.start, token.start),
274
+ code="unexpected_token",
275
+ )
276
+ self.position += 1
277
+ children.append(token)
278
+ else:
279
+ children.append(self._production(symbol.name))
280
+ return ParseNode(name, alternative_number, tuple(children))
281
+
282
+ def _recognize_production(self, name: str) -> None:
283
+ development = self._require_development()
284
+ alternatives = development.resolved.productions[name]
285
+ matches = [
286
+ alternative
287
+ for alternative_number, alternative in enumerate(alternatives, start=1)
288
+ if any(
289
+ self._lookahead_matches(word)
290
+ for word in development.analysis.select[(name, alternative_number)]
291
+ )
292
+ ]
293
+ if len(matches) != 1:
294
+ lookahead = [
295
+ token.type
296
+ for token in self.tokens[
297
+ self.position : self.position + development.analysis.k
298
+ ]
299
+ ]
300
+ offset = self._current_offset()
301
+ raise BslParseError(
302
+ f"No unique alternative for {name} at {lookahead}",
303
+ span=SourceSpan(offset, offset),
304
+ code="ambiguous_alternative",
305
+ )
306
+ for symbol in matches[0].symbols:
307
+ if hasattr(symbol, "token_types"):
308
+ if self.position >= len(self.tokens):
309
+ offset = self._current_offset()
310
+ raise BslParseError(
311
+ f"Unexpected end while parsing {name}",
312
+ span=SourceSpan(offset, offset),
313
+ code="unexpected_end",
314
+ )
315
+ token = self.tokens[self.position]
316
+ if token.type not in symbol.token_types:
317
+ raise BslParseError(
318
+ f"Expected {sorted(symbol.token_types)}, got "
319
+ f"{token.type} at {token.start}",
320
+ span=SourceSpan(token.start, token.start),
321
+ code="unexpected_token",
322
+ )
323
+ self.position += 1
324
+ else:
325
+ self._recognize_production(symbol.name)
326
+
327
+ @property
328
+ def lookahead(self) -> int:
329
+ return self._require_development().analysis.k
330
+
331
+ @property
332
+ def parser_ir(self) -> Any:
333
+ return self._require_development().parser_ir
334
+
335
+ @property
336
+ def validation_warnings(self) -> tuple[dict[str, str], ...]:
337
+ return self._require_development().validation_warnings
338
+
339
+ def _current_offset(self) -> int:
340
+ if self.position < len(self.tokens):
341
+ return self.tokens[self.position].start
342
+ return self.tokens[-1].end if self.tokens else 0
343
+
344
+ def _require_development(self) -> DevelopmentParserDetails:
345
+ if self.development is None:
346
+ raise RuntimeError(
347
+ "Interpreted parser details are available only from from_files()"
348
+ )
349
+ return self.development
350
+
351
+
352
+ def parse_raw_module(
353
+ source: str,
354
+ parser_target: PythonParserTarget,
355
+ ) -> tuple[Any, tuple[Token, ...]]:
356
+ """Parse a raw BSL module while retaining directive-covered source code.
357
+
358
+ Each leading preprocessor line is validated by the grammar's directive
359
+ entrypoint. Only those line tokens are omitted from the module token view;
360
+ all returned tokens and AST spans keep their offsets in ``source``.
361
+ """
362
+ tokens = tuple(tokenize(source))
363
+ module_tokens: list[Token] = []
364
+ position = 0
365
+ while position < len(tokens):
366
+ token = tokens[position]
367
+ line_start = source.rfind("\n", 0, token.start) + 1
368
+ indentation = source[line_start : token.start]
369
+ if token.type != "#" or not all(
370
+ character.isspace() for character in indentation
371
+ ):
372
+ module_tokens.append(token)
373
+ position += 1
374
+ continue
375
+
376
+ line_end = source.find("\n", token.end)
377
+ if line_end < 0:
378
+ line_end = len(source)
379
+ directive_start = position
380
+ while position < len(tokens) and tokens[position].start < line_end:
381
+ position += 1
382
+ parser_target.parse_tokens_ast(
383
+ tokens[directive_start:position],
384
+ "ДирективаПрепроцессора",
385
+ )
386
+
387
+ root = parser_target.parse_tokens_ast(tuple(module_tokens), "Модуль")
388
+ return root, tokens
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ def _blank(line: str) -> str:
5
+ if line.endswith("\r\n"):
6
+ return "\r\n"
7
+ if line.endswith("\n") or line.endswith("\r"):
8
+ return line[-1]
9
+ return ""
10
+
11
+
12
+ def preprocess_server_source(source: str) -> str:
13
+ return "".join(
14
+ _blank(line) if line.lstrip().startswith(("#", "&")) else line
15
+ for line in source.splitlines(keepends=True)
16
+ )