infinity-data 1.1.0__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {infinity_data-1.1.0/src/infinity_data.egg-info → infinity_data-1.2.0}/PKG-INFO +1 -1
- {infinity_data-1.1.0 → infinity_data-1.2.0}/pyproject.toml +4 -1
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/parser/diagnostics.py +5 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/parser/parser.py +22 -2
- infinity_data-1.2.0/src/infinity_data/py.typed +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/registry/dict_constraints.py +13 -4
- {infinity_data-1.1.0 → infinity_data-1.2.0/src/infinity_data.egg-info}/PKG-INFO +1 -1
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data.egg-info/SOURCES.txt +1 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/LICENSE +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/README.md +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/setup.cfg +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/emit/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/emit/converter.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/frontend.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/infra/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/infra/diagnostics.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/infra/file.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/infra/ll1_stream.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/infra/location.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/infra/path.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/parser/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/parser/models.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/parser/token_stream.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/pipeline.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/sandbox/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/sandbox/config.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/sandbox/errors.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/sandbox/mediator.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/sandbox/schema.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/builder/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/builder/builder.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/builder/models.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/constraints.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/diagnostics.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/executor/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/executor/executor.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/registry/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/registry/_core.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/registry/general.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/registry/logic.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/registry/types.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/resolver/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/resolver/imports.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/resolver/models.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/resolver/resolver.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/tokenizer/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/tokenizer/char_stream.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/tokenizer/diagnostics.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/tokenizer/finalizer.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/tokenizer/models/__init__.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/tokenizer/models/raw_tokens.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/tokenizer/models/tokens.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/tokenizer/tokenizer.py +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data.egg-info/dependency_links.txt +0 -0
- {infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "infinity-data"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.2.0"
|
|
4
4
|
description = "InfinityData:声明式配置语言(.infd/.inft)的 Python 编译器库"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -57,6 +57,9 @@ package-dir = {"" = "src"}
|
|
|
57
57
|
[tool.setuptools.packages.find]
|
|
58
58
|
where = ["src"]
|
|
59
59
|
|
|
60
|
+
[tool.setuptools.package-data]
|
|
61
|
+
infinity_data = ["py.typed"]
|
|
62
|
+
|
|
60
63
|
[tool.ruff]
|
|
61
64
|
line-length = 120
|
|
62
65
|
target-version = "py312"
|
|
@@ -48,6 +48,11 @@ register_diagnostic_define(
|
|
|
48
48
|
'[{location}] 导入项之间必须用逗号分隔(import 列表不接受换行/空格分隔)',
|
|
49
49
|
en='[{location}] import items must be separated by commas (newlines/spaces are not allowed)',
|
|
50
50
|
),
|
|
51
|
+
diagnostic_define(
|
|
52
|
+
'parse.import_requires_newline',
|
|
53
|
+
'[{location}] 导入语句必须以换行结尾(同一行逗号后不能再接其他语句)',
|
|
54
|
+
en='[{location}] import statement must end with a newline (cannot be followed by more tokens on the same line)',
|
|
55
|
+
),
|
|
51
56
|
diagnostic_define(
|
|
52
57
|
'parse.value_field',
|
|
53
58
|
'[{location}] 值位置出现字段定义 {name}(外层数组/对象未闭合)',
|
|
@@ -138,8 +138,13 @@ class Parser:
|
|
|
138
138
|
|
|
139
139
|
@staticmethod
|
|
140
140
|
def _parse_statement(stream: TokenStream, collector: DiagnosticCollector) -> Statement | None:
|
|
141
|
-
"""解析一条顶层语句。
|
|
142
|
-
|
|
141
|
+
"""解析一条顶层语句。
|
|
142
|
+
|
|
143
|
+
顶层与块内一致,接受**逗号或换行**分隔(二者等价,可混用)——
|
|
144
|
+
整个文件(含模板定义、字段、结构级约束)可压缩成一行;
|
|
145
|
+
导入语句内部仍强制逗号分隔(见 §3.2)。
|
|
146
|
+
"""
|
|
147
|
+
stream.skip_separators()
|
|
143
148
|
|
|
144
149
|
# EofToken 或物理耗尽均视为流结束
|
|
145
150
|
if stream.eof():
|
|
@@ -223,6 +228,21 @@ class Parser:
|
|
|
223
228
|
stream.advance()
|
|
224
229
|
alias = stream.expect(IdentifierToken).name
|
|
225
230
|
|
|
231
|
+
# 导入语句必须换行/EOF 结尾:!env 无导入项列表,若不加检查,同一行的逗号会被
|
|
232
|
+
# 顶层 skip_separators 吞掉(`!env import A as a, x = 1` 被误认为合法),与
|
|
233
|
+
# !from / !file 的「尾部必须换行」行为不一致。
|
|
234
|
+
tok = stream.peek()
|
|
235
|
+
# 显式排除 NoNextType 以收窄类型:stream.eof() 是方法调用,无法据此收窄 tok,
|
|
236
|
+
# 否则 tok 仍为 Token | NoNextType,访问 tok.raw 会触发类型错误。
|
|
237
|
+
if not isinstance(tok, NoNextType) and not (stream.eof() or isinstance(tok, NewlineToken)):
|
|
238
|
+
collector.add(
|
|
239
|
+
diag(
|
|
240
|
+
'parse.import_requires_newline',
|
|
241
|
+
{'actual': tok.raw.type.name},
|
|
242
|
+
stream.single_span(tok),
|
|
243
|
+
)
|
|
244
|
+
)
|
|
245
|
+
|
|
226
246
|
# 注意:不在此消费尾部换行——语句间分隔由 _parse_statement 开头统一处理,
|
|
227
247
|
# 否则语句 source 会把下一行行首吞入(与 Field 不一致)
|
|
228
248
|
return EnvImportStmt(
|
|
File without changes
|
{infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/semantic/registry/dict_constraints.py
RENAMED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
"""内置字典约束:has / field。
|
|
1
|
+
"""内置字典约束:has / field。
|
|
2
|
+
|
|
3
|
+
与三态可空的交互:``noexist`` 字段(键不出现)对二者均视为**不存在**——
|
|
4
|
+
``has(noexist字段)`` 不满足、``field(noexist字段, c)`` 视为字段缺失。
|
|
5
|
+
(noexist 在 StdObject 中是非 None 哨兵,渲染时才过滤,须显式排除。)
|
|
6
|
+
"""
|
|
2
7
|
|
|
3
8
|
from __future__ import annotations
|
|
4
9
|
|
|
@@ -19,7 +24,7 @@ from infinity_data.semantic.registry._core import (
|
|
|
19
24
|
)
|
|
20
25
|
from infinity_data.tokenizer.models.raw_tokens import SourceRange
|
|
21
26
|
|
|
22
|
-
__all__ = ['
|
|
27
|
+
__all__ = ['_check_field', '_check_has']
|
|
23
28
|
|
|
24
29
|
|
|
25
30
|
def _check_has(
|
|
@@ -32,7 +37,10 @@ def _check_has(
|
|
|
32
37
|
if not isinstance(val, StdObject):
|
|
33
38
|
return fail_result('constraint.has_only', {}, source, path)
|
|
34
39
|
key = _spec_name(args[0])
|
|
35
|
-
|
|
40
|
+
f = val.get(key)
|
|
41
|
+
# noexist 字段在 StdObject 中仍以非 None 哨兵存在(渲染时才过滤),
|
|
42
|
+
# 但按三态语义「键不出现」应视为不存在(回归:one(has(a), has(b)) 误判 both)。
|
|
43
|
+
if f is not None and not f.is_noexist:
|
|
36
44
|
return ok_result()
|
|
37
45
|
return fail_result('constraint.has_missing', {'key': key}, source, path)
|
|
38
46
|
|
|
@@ -51,6 +59,7 @@ def _check_field(
|
|
|
51
59
|
if spec is None:
|
|
52
60
|
return fail_result('constraint.field_need', {}, source, path)
|
|
53
61
|
f = val.get(name)
|
|
54
|
-
|
|
62
|
+
# noexist = 键不出现 → 视为字段缺失(与 has 同理)
|
|
63
|
+
if f is None or f.is_noexist:
|
|
55
64
|
return fail_result('constraint.field_missing', {'field': name}, source, path)
|
|
56
65
|
return executor(spec, f.value, source, f'{path}.{name}')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{infinity_data-1.1.0 → infinity_data-1.2.0}/src/infinity_data/tokenizer/models/raw_tokens.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|