feat(lang): 同步 cif/celif/celse、值引用注解与 assert 改译 testcheck.check
vast 双路径(Python Parser/ExprParser 与 C 扩展 vast_c.c)新增 cif-celif-celse 语句族与 &T / &temp T 参数注解解析,_parser.pyd 已同步重编。HandlesIf 改认 @CIf 标记并做编译期常量求值,含运行时变量一律 fail-fast,同时删除 c.CIf 家族(c.py)。HandlesAssert 合成 testcheck.check(cond, None, msg) 调用,非字符串字面量消息报 TypeError。FuncGen 调用点按形参模式自动取址(ref 仅接受左值,右值 fail-fast;temp 物化临时栈),SymbolUtils/TypeAnnotationResolver 提供模式识别;t.py 删除 CNeedPtr。
This commit is contained in:
1 parent
64f3d79b64
commit
2514cee4c9
24 files changed
+1139
-246
No files matched your search
@@ -1274,6 +1274,11 @@ class DeclarationGenerator:
|
||||
return f'{sname}*'
|
||||
elif isinstance(annotation, ast.Attribute):
|
||||
attr_name: str = annotation.attr if hasattr(annotation, 'attr') else ''
|
||||
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按 t.CPtr
|
||||
# 同形的「一层指针 = i8*」参与联合合并(`T | t.CRef` → T*),保证跨模块
|
||||
# .vpi 声明端类型与定义端 _ctype_to_llvm 一致。
|
||||
if attr_name in ('CRef', 'CTempRef'):
|
||||
return 'i8*'
|
||||
module_name: str = ''
|
||||
if hasattr(annotation, 'value'):
|
||||
if isinstance(annotation.value, ast.Name):
|
||||
|
||||
@@ -152,6 +152,22 @@ class Phase1Generator:
|
||||
deps: set[str] = get_file_dependencies(src_path, self.src_root)
|
||||
imported_from_src.update(deps)
|
||||
|
||||
# 检测 assert 使用,自动添加 testcheck 依赖:assert 译为
|
||||
# testcheck.check(...),该 include 须纳入 .vpi/.stub 生成与后续编译链接,
|
||||
# 否则断言所在模块解析不到 testcheck.check(跨模块符号缺失)。
|
||||
# 独立成一次 walk:下面的 dict/list 检测循环带 break,会漏掉其后的 assert。
|
||||
for src_path in reachable_source_files:
|
||||
try:
|
||||
_, tree = parse_python_file(src_path)
|
||||
if tree is None:
|
||||
continue
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Assert):
|
||||
imported_from_src.add('testcheck')
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 检测 dict/list 容器使用,自动添加 _dict/_list/json 依赖
|
||||
for src_path in reachable_source_files:
|
||||
try:
|
||||
|
||||
@@ -1547,6 +1547,10 @@ class Phase2Translator:
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
if node.module:
|
||||
self.used_includes.add(node.module.split('.')[0])
|
||||
# 检测 assert 使用,自动添加 testcheck 到 used_includes:
|
||||
# assert 译为 testcheck.check(...),该库须被发现、编译并链接。
|
||||
if isinstance(node, ast.Assert):
|
||||
self.used_includes.add('testcheck')
|
||||
# 检测 list/dict 容器使用,自动添加 _list/_dict/json 到 used_includes
|
||||
# 以便 _scan_include_libraries 能发现并编译这些库文件
|
||||
if isinstance(node, ast.Subscript) and isinstance(node.value, ast.Name):
|
||||
@@ -2144,11 +2148,14 @@ class Phase2Translator:
|
||||
def _inject_auto_imports(self, code: str, src_path: str) -> str:
|
||||
"""检测源码中对 list/dict 容器的使用,自动注入 import _list / import _dict。
|
||||
当使用 dict 时,同时注入 import json (用于 dict 的 JSON 处理功能)。
|
||||
检测到 assert 语句时自动注入 import testcheck(assert 译为
|
||||
testcheck.check(...),需该模块的跨模块符号声明)。
|
||||
|
||||
检测模式:
|
||||
- list[T] / dict[V] 作为类型注解 (ast.Subscript, value=Name(id='list'/'dict'))
|
||||
- list[T](...) / dict[V](...) 作为构造函数调用 (ast.Call, func=Subscript)
|
||||
- list(...) / dict(...) 作为构造函数调用 (ast.Call, func=Name)
|
||||
- assert 语句 (ast.Assert)
|
||||
"""
|
||||
try:
|
||||
# `.vp` 源码须先过 Viper 软关键字层(`enum X:` / `fn` 等)再解析:
|
||||
@@ -2158,10 +2165,11 @@ class Phase2Translator:
|
||||
except SyntaxError:
|
||||
return code
|
||||
|
||||
# 检查是否已经导入了 _list / _dict / json
|
||||
# 检查是否已经导入了 _list / _dict / json / testcheck
|
||||
has_list_import: bool = False
|
||||
has_dict_import: bool = False
|
||||
has_json_import: bool = False
|
||||
has_testcheck_import: bool = False
|
||||
for node in ast.iter_child_nodes(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
for alias in node.names:
|
||||
@@ -2171,6 +2179,8 @@ class Phase2Translator:
|
||||
has_dict_import = True
|
||||
elif alias.name == 'json':
|
||||
has_json_import = True
|
||||
elif alias.name == 'testcheck':
|
||||
has_testcheck_import = True
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
if node.module == '_list':
|
||||
has_list_import = True
|
||||
@@ -2178,13 +2188,18 @@ class Phase2Translator:
|
||||
has_dict_import = True
|
||||
elif node.module == 'json':
|
||||
has_json_import = True
|
||||
if has_list_import and has_dict_import and has_json_import:
|
||||
elif node.module == 'testcheck':
|
||||
has_testcheck_import = True
|
||||
if has_list_import and has_dict_import and has_json_import and has_testcheck_import:
|
||||
break
|
||||
|
||||
# 检查是否使用了 list / dict 容器
|
||||
# 检查是否使用了 list / dict 容器,以及是否含 assert 语句
|
||||
uses_list: bool = False
|
||||
uses_dict: bool = False
|
||||
uses_assert: bool = False
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Assert):
|
||||
uses_assert = True
|
||||
if isinstance(node, ast.Subscript):
|
||||
if isinstance(node.value, ast.Name):
|
||||
if node.value.id == 'list':
|
||||
@@ -2211,6 +2226,9 @@ class Phase2Translator:
|
||||
prefix += 'import _dict\n'
|
||||
if uses_dict and not has_json_import:
|
||||
prefix += 'import json\n'
|
||||
# 含 assert 的模块等价于在文件顶部写下 import testcheck(已导入则不重复)
|
||||
if uses_assert and not has_testcheck_import:
|
||||
prefix += 'import testcheck\n'
|
||||
if prefix:
|
||||
return prefix + code
|
||||
return code
|
||||
|
||||
+126
-60
@@ -220,14 +220,14 @@ class PythonToStubConverter:
|
||||
StubLines.append('')
|
||||
StubLines.append(ImportStr)
|
||||
elif isinstance(node, ast.Expr):
|
||||
# 处理模块级别的宏调用,如 c.CIf(...), c.CEndif()
|
||||
# 处理模块级别的宏调用,如 c.CEndif()
|
||||
ExprStr: str = PythonToStubConverter._GetExprString(node.value)
|
||||
if ExprStr:
|
||||
CurrentType = 'macro'
|
||||
StubLines.append(ExprStr)
|
||||
StubLines.append('') # 宏后空行
|
||||
elif isinstance(node, ast.If):
|
||||
# 处理模块级别的 if 宏条件,如 if c.CIf(FF_MULTI_PARTITION):
|
||||
# 处理模块级别的 cif 宏条件,如 `cif FF_MULTI_PARTITION:`
|
||||
IfStr: str = PythonToStubConverter._GetModuleIfMacroString(node)
|
||||
if IfStr:
|
||||
CurrentType = 'macro'
|
||||
@@ -440,12 +440,12 @@ class PythonToStubConverter:
|
||||
FuncStub: list[str] = PythonToStubConverter._ConvertFunction(item, indent=indent+1, SourceLines=SourceLines, class_name=node.name)
|
||||
lines.extend(FuncStub)
|
||||
elif isinstance(item, ast.Expr):
|
||||
# 处理宏调用,如 c.CIf(...), c.CEndif(), c.CElif(), c.CElse()
|
||||
# 处理宏调用,如 c.CEndif()
|
||||
ExprStr: str = PythonToStubConverter._GetExprString(item.value)
|
||||
if ExprStr:
|
||||
lines.append(f'{IndentStr} {ExprStr}')
|
||||
elif isinstance(item, ast.If):
|
||||
# 处理 if c.CIf(...): 形式的宏条件
|
||||
# 处理 cif 宏条件(`cif ...:` / `celif ...:` / `celse:`)
|
||||
IfStr: str = PythonToStubConverter._get_if_macro_string(item, indent=indent+1)
|
||||
if IfStr:
|
||||
lines.append(IfStr)
|
||||
@@ -710,6 +710,21 @@ class PythonToStubConverter:
|
||||
left: ast.AST = annotation.left
|
||||
right: ast.AST = annotation.right
|
||||
|
||||
# 值引用参数标记:联合形态 `T | t.CRef`(ref)/ `T | t.CTempRef`(temp)
|
||||
# 还原为源码写法 `&T` / `&temp T`,使跨模块 .vpi 往返保留取址模式。
|
||||
if isinstance(annotation.op, ast.BitOr):
|
||||
_ref_kind: str | None = None
|
||||
_type_side: ast.AST | None = None
|
||||
if isinstance(right, ast.Attribute) and right.attr in ('CRef', 'CTempRef'):
|
||||
_ref_kind = right.attr
|
||||
_type_side = left
|
||||
elif isinstance(left, ast.Attribute) and left.attr in ('CRef', 'CTempRef'):
|
||||
_ref_kind = left.attr
|
||||
_type_side = right
|
||||
if _ref_kind is not None and _type_side is not None:
|
||||
_inner: str = PythonToStubConverter._GetTypeString(_type_side)
|
||||
return f'&temp {_inner}' if _ref_kind == 'CTempRef' else f'&{_inner}'
|
||||
|
||||
# 检查右侧是否是 __set_default__ 调用
|
||||
if isinstance(right, ast.Call) and isinstance(right.func, ast.Attribute) and right.func.attr in ('__set_default__', '__set_default'):
|
||||
# 去除 __set_default__,保留左侧,右侧替换为函数名部分
|
||||
@@ -973,81 +988,132 @@ class PythonToStubConverter:
|
||||
def _GetExprString(expr: ast.AST) -> str:
|
||||
"""获取表达式字符串(用于宏调用)"""
|
||||
if isinstance(expr, ast.Call):
|
||||
# 处理函数调用,如 c.CIf(...), c.CEndif(), c.CUndef(...), c.CPragma(...)
|
||||
# 处理函数调用,如 c.CEndif(), c.CUndef(...), c.CPragma(...)
|
||||
# (旧的 c.CIf/c.CElif/c.CElse 已删除:cif/celif/celse 由 _ProcessIfMacro 渲染)
|
||||
FuncStr: str = PythonToStubConverter._GetDecoratorString(expr.func)
|
||||
if FuncStr and ('CIf' in FuncStr or 'CEndif' in FuncStr or 'CElif' in FuncStr or 'CElse' in FuncStr or 'CUndef' in FuncStr or 'CPragma' in FuncStr):
|
||||
if FuncStr and ('CEndif' in FuncStr or 'CUndef' in FuncStr or 'CPragma' in FuncStr):
|
||||
ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in expr.args])
|
||||
return f'{FuncStr}({ArgsStr})' if ArgsStr else f'{FuncStr}()'
|
||||
return ''
|
||||
|
||||
@staticmethod
|
||||
def _RestoreDefinedMarkers(node: ast.AST) -> ast.AST:
|
||||
"""把内部标记 c.CIfdef(N) 递归还原为 defined(N) 调用(供 stub 文本渲染)。
|
||||
|
||||
cif/celif 条件的 desugar 会把 defined(NAME) 变成 c.@CIfdef(NAME) 标记调用;
|
||||
生成 .vpi 文本时必须还原为用户可写的 defined(NAME),否则存根不可再解析。
|
||||
"""
|
||||
if isinstance(node, ast.Call):
|
||||
F: str = PythonToStubConverter._GetDecoratorString(node.func)
|
||||
short: str = F.rsplit('.', 1)[-1] if F else ''
|
||||
if short in ('@CIfdef', '@CIfndef') and len(node.args) == 1:
|
||||
inner: ast.AST = PythonToStubConverter._RestoreDefinedMarkers(node.args[0])
|
||||
call: ast.Call = ast.Call(
|
||||
func=ast.Name(id='defined', ctx=ast.Load()),
|
||||
args=[inner], keywords=[])
|
||||
if short == '@CIfndef':
|
||||
return ast.UnaryOp(op=ast.Not(), operand=call)
|
||||
return call
|
||||
for field, value in ast.iter_fields(node):
|
||||
if isinstance(value, list):
|
||||
for i, item in enumerate(value):
|
||||
if isinstance(item, ast.AST):
|
||||
value[i] = PythonToStubConverter._RestoreDefinedMarkers(item)
|
||||
elif isinstance(value, ast.AST):
|
||||
setattr(node, field, PythonToStubConverter._RestoreDefinedMarkers(value))
|
||||
return node
|
||||
|
||||
@staticmethod
|
||||
def _CifConditionText(test: ast.AST) -> str | None:
|
||||
"""cif/celif 条件文本:内部标记 c.@CIf(EXPR) → EXPR;c.@CIfdef(N) → defined(N)。
|
||||
|
||||
返回 None 表示 test 不是 cif 族标记(普通 if 的运行时条件)。
|
||||
"""
|
||||
if isinstance(test, ast.Call):
|
||||
F: str = PythonToStubConverter._GetDecoratorString(test.func)
|
||||
short: str = F.rsplit('.', 1)[-1] if F else ''
|
||||
if short == '@CIf' and len(test.args) == 1:
|
||||
inner: ast.AST = PythonToStubConverter._RestoreDefinedMarkers(test.args[0])
|
||||
return PythonToStubConverter._GetTypeString(inner)
|
||||
if short in ('@CIfdef', '@CIfndef') and len(test.args) == 1:
|
||||
return PythonToStubConverter._GetTypeString(
|
||||
PythonToStubConverter._RestoreDefinedMarkers(test))
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _get_if_macro_string(node: ast.If, indent: int = 1) -> str:
|
||||
"""获取类内部的 if 宏字符串(如 if c.CIf(...):)"""
|
||||
"""获取类内部的 cif 宏字符串(如 `cif <cond>:`,含 celif/celse 链)。"""
|
||||
IndentStr: str = ' ' * indent
|
||||
InnerIndent: str = ' ' * (indent + 1)
|
||||
# 检查条件是否是宏调用
|
||||
if isinstance(node.test, ast.Call):
|
||||
FuncStr: str = PythonToStubConverter._GetDecoratorString(node.test.func)
|
||||
if FuncStr and 'CIf' in FuncStr:
|
||||
ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args])
|
||||
result: list[str] = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():']
|
||||
# 处理 if 体内的语句
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.AnnAssign):
|
||||
TypeStr: str = PythonToStubConverter._GetTypeString(item.annotation)
|
||||
result.append(f'{InnerIndent}{item.target.id}: {TypeStr}')
|
||||
elif isinstance(item, ast.Expr):
|
||||
ExprStr: str = PythonToStubConverter._GetExprString(item.value)
|
||||
if ExprStr:
|
||||
result.append(f'{InnerIndent}{ExprStr}')
|
||||
return '\n'.join(result)
|
||||
return ''
|
||||
cond: str | None = PythonToStubConverter._CifConditionText(node.test)
|
||||
if cond is None:
|
||||
return ''
|
||||
|
||||
def _body_lines(body: list, ind: str) -> list[str]:
|
||||
out: list[str] = []
|
||||
for item in body:
|
||||
if isinstance(item, ast.AnnAssign):
|
||||
TypeStr: str = PythonToStubConverter._GetTypeString(item.annotation)
|
||||
out.append(f'{ind}{item.target.id}: {TypeStr}')
|
||||
elif isinstance(item, ast.Expr):
|
||||
ExprStr: str = PythonToStubConverter._GetExprString(item.value)
|
||||
if ExprStr:
|
||||
out.append(f'{ind}{ExprStr}')
|
||||
return out
|
||||
|
||||
result: list[str] = [f'{IndentStr}cif {cond}:']
|
||||
result.extend(_body_lines(node.body, InnerIndent))
|
||||
current: ast.If = node
|
||||
while current.orelse:
|
||||
if len(current.orelse) == 1 and isinstance(current.orelse[0], ast.If):
|
||||
elif_node: ast.If = current.orelse[0]
|
||||
econd: str | None = PythonToStubConverter._CifConditionText(elif_node.test)
|
||||
if econd is None:
|
||||
break
|
||||
result.append(f'{IndentStr}celif {econd}:')
|
||||
result.extend(_body_lines(elif_node.body, InnerIndent))
|
||||
current = elif_node
|
||||
continue
|
||||
result.append(f'{IndentStr}celse:')
|
||||
result.extend(_body_lines(current.orelse, InnerIndent))
|
||||
break
|
||||
return '\n'.join(result)
|
||||
|
||||
@staticmethod
|
||||
def _GetModuleIfMacroString(node: ast.If) -> str:
|
||||
"""获取模块级别的 if 宏字符串(如 if c.CIf(FF_MULTI_PARTITION):)"""
|
||||
"""获取模块级别的 cif 宏字符串(如 `cif FF_MULTI_PARTITION:`)。"""
|
||||
return PythonToStubConverter._ProcessIfMacro(node, indent=0)
|
||||
|
||||
@staticmethod
|
||||
def _ProcessIfMacro(node: ast.If, indent: int = 0) -> str:
|
||||
"""处理 if 宏节点,支持 elif 和 else"""
|
||||
"""处理 cif 宏节点,支持 celif / celse 链。"""
|
||||
IndentStr: str = ' ' * indent
|
||||
cond: str | None = PythonToStubConverter._CifConditionText(node.test)
|
||||
if cond is None:
|
||||
return ''
|
||||
result: list[str] = [f'{IndentStr}cif {cond}:']
|
||||
for item in node.body:
|
||||
result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1))
|
||||
|
||||
# 检查条件是否是宏调用
|
||||
if isinstance(node.test, ast.Call):
|
||||
FuncStr: str = PythonToStubConverter._GetDecoratorString(node.test.func)
|
||||
if FuncStr and 'CIf' in FuncStr:
|
||||
ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args])
|
||||
result: list[str] = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():']
|
||||
# 处理 if 体内的语句
|
||||
for item in node.body:
|
||||
current: ast.If = node
|
||||
while current.orelse:
|
||||
if len(current.orelse) == 1 and isinstance(current.orelse[0], ast.If):
|
||||
# celif 情况
|
||||
elif_node: ast.If = current.orelse[0]
|
||||
econd: str | None = PythonToStubConverter._CifConditionText(elif_node.test)
|
||||
if econd is None:
|
||||
break
|
||||
result.append(f'{IndentStr}celif {econd}:')
|
||||
for item in elif_node.body:
|
||||
result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1))
|
||||
|
||||
# 处理 elif 和 else
|
||||
current: ast.If = node
|
||||
while current.orelse:
|
||||
if len(current.orelse) == 1 and isinstance(current.orelse[0], ast.If):
|
||||
# elif 情况
|
||||
elif_node: ast.If = current.orelse[0]
|
||||
if isinstance(elif_node.test, ast.Call):
|
||||
ElifFuncStr: str = PythonToStubConverter._GetDecoratorString(elif_node.test.func)
|
||||
if ElifFuncStr and 'CIf' in ElifFuncStr:
|
||||
ElifArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in elif_node.test.args])
|
||||
result.append(f'{IndentStr}elif {ElifFuncStr}({ElifArgsStr}):' if ElifArgsStr else f'{IndentStr}elif {ElifFuncStr}():')
|
||||
for item in elif_node.body:
|
||||
result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1))
|
||||
current = elif_node
|
||||
continue
|
||||
break
|
||||
else:
|
||||
# else 情况
|
||||
result.append(f'{IndentStr}else:')
|
||||
for item in current.orelse:
|
||||
result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1))
|
||||
break
|
||||
|
||||
return '\n'.join(result)
|
||||
return ''
|
||||
current = elif_node
|
||||
continue
|
||||
# celse 情况
|
||||
result.append(f'{IndentStr}celse:')
|
||||
for item in current.orelse:
|
||||
result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1))
|
||||
break
|
||||
return '\n'.join(result)
|
||||
|
||||
@staticmethod
|
||||
def _ProcessMacroBodyItem(item: ast.AST, indent: int = 0) -> list[str]:
|
||||
|
||||
@@ -222,6 +222,28 @@ class ConstEvaluator:
|
||||
elif isinstance(func, ast.Name):
|
||||
func_name = func.id
|
||||
|
||||
# c.@CIfdef(NAME) / c.@CIfndef(NAME):defined(NAME) 的解析期 desugar 标记,编译期返回 0/1。
|
||||
# 仅出现在 cif/celif 条件内(解析器保证),故此处只做宏定义判定。
|
||||
if func_name == '@CIfdef':
|
||||
if node.args:
|
||||
macro_name: str | None = ConstEvaluator._resolve_macro_ref(node.args[0], ctx)
|
||||
if macro_name is not None:
|
||||
return 1 if ctx.is_macro_defined(macro_name) else 0
|
||||
return 0
|
||||
if func_name == '@CIfndef':
|
||||
if node.args:
|
||||
macro_name = ConstEvaluator._resolve_macro_ref(node.args[0], ctx)
|
||||
if macro_name is not None:
|
||||
return 0 if ctx.is_macro_defined(macro_name) else 1
|
||||
return 1
|
||||
# defined(NAME) 谓词(未 desugar 形态 / TPV 口径):编译期返回 0/1。
|
||||
if func_name == 'defined' and module_name is None:
|
||||
if node.args:
|
||||
macro_name = ConstEvaluator._resolve_macro_ref(node.args[0], ctx)
|
||||
if macro_name is not None:
|
||||
return 1 if ctx.is_macro_defined(macro_name) else 0
|
||||
return 0
|
||||
|
||||
# ctraits.isptr(x) — 带模块前缀
|
||||
# isptr(x) — 通过 from ctraits import isptr 导入
|
||||
is_isptr: bool = False
|
||||
@@ -434,6 +456,17 @@ class ConstEvaluator:
|
||||
pass
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _resolve_macro_ref(node: ast.AST, ctx: 'EvalContext') -> Optional[str]:
|
||||
"""从 defined(...) 实参节点解析宏名:Name→id;Constant(str)→值;Attribute→点分全名。"""
|
||||
if isinstance(node, ast.Name):
|
||||
return node.id
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, str):
|
||||
return node.value
|
||||
if isinstance(node, ast.Attribute):
|
||||
return EvalContext._get_attr_full_name(node)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _eval_attribute_define(node: ast.Attribute, symtab: Any) -> Optional[Any]:
|
||||
"""从 SymbolTable 查找 Attribute 形式的 define 值"""
|
||||
@@ -532,7 +565,39 @@ class EvalContext:
|
||||
|
||||
return None
|
||||
|
||||
def lookup_attribute(self, node: ast.Attribute) -> Optional[Any]:
|
||||
def is_macro_defined(self, name: str) -> bool:
|
||||
"""判定宏 NAME 是否已定义(供 defined(NAME) / c.CIfdef 标记使用)。
|
||||
|
||||
来源与 HandlesIf._is_macro_defined 同口径:Gen._define_constants /
|
||||
_DefineConstants / SymbolTable.is_define / 平台宏。
|
||||
"""
|
||||
if not name:
|
||||
return False
|
||||
if self.Gen and name in getattr(self.Gen, '_define_constants', {}):
|
||||
return True
|
||||
if self.Gen and hasattr(self.Gen, '_DefineConstants') and name in self.Gen._DefineConstants:
|
||||
return True
|
||||
if self.symtab:
|
||||
is_define = getattr(self.symtab, 'is_define', None)
|
||||
if callable(is_define) and is_define(name):
|
||||
return True
|
||||
if hasattr(self.symtab, '__contains__') and name in self.symtab:
|
||||
info: CTypeInfo = self.symtab[name]
|
||||
if getattr(info, 'IsDefine', False):
|
||||
return True
|
||||
macros: dict = self._get_platform_macros()
|
||||
if name in macros:
|
||||
return True
|
||||
# Attribute 形式(如 platmacro.IS_WINDOWS):退化为短名匹配。
|
||||
if '.' in name:
|
||||
short: str = name.rsplit('.', 1)[-1]
|
||||
if short in macros:
|
||||
return True
|
||||
if self.Gen and short in getattr(self.Gen, '_define_constants', {}):
|
||||
return True
|
||||
return False
|
||||
|
||||
def lookup_attribute(self, node: ast.Attribute) -> Optional[Any]:
|
||||
"""查找 Attribute 节点的值"""
|
||||
module_name: str | None = node.value.id if isinstance(node.value, ast.Name) else None
|
||||
attr_name: str = node.attr
|
||||
|
||||
@@ -12,6 +12,7 @@ from lib.includes import t
|
||||
from lib.core.SymbolUtils import (
|
||||
IsListAnnotation, ParseListAnnotation, FindStructNameInAnnotationWithContext,
|
||||
AnnotationContainsName, IsCPtrNode, RequireDefineConstStorable,
|
||||
FindAutoAddrMode,
|
||||
)
|
||||
|
||||
|
||||
@@ -38,7 +39,8 @@ def _IsGenericTpName(name: str) -> bool:
|
||||
_PTR_MARKER_CLASS_NAMES: frozenset[str] = frozenset({
|
||||
'rawptr', 't.rawptr', 'c.rawptr',
|
||||
'CPtr', 't.CPtr', 'c.CPtr',
|
||||
'CNeedPtr', 't.CNeedPtr', 'CAutoPtr', 't.CAutoPtr',
|
||||
'CAutoPtr', 't.CAutoPtr',
|
||||
'CRef', 't.CRef', 'CTempRef', 't.CTempRef',
|
||||
})
|
||||
|
||||
|
||||
@@ -501,6 +503,14 @@ class AnnAssignHandle(BaseHandle):
|
||||
|
||||
def _HandleAnnAssignLlvmInner(self, Node: ast.AnnAssign) -> None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
# 值引用标记(`&T` / `&temp T`)仅用于函数参数位:局部/全局变量注解出现即 fail-fast。
|
||||
_ref_mode: str | None = FindAutoAddrMode(Node.annotation)
|
||||
if _ref_mode is not None:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
_ann_text: str = ast.unparse(Node.annotation)
|
||||
raise FailFastError(
|
||||
f"变量注解不支持值引用(`&T` / `&temp T`):'{_ann_text}'。"
|
||||
f"值引用仅用于函数参数位;局部变量请改用显式指针类型(如 `T*`)。")
|
||||
# 内建定长数组构造子 array 的注解校验(误用即 fail-fast,含文件:行:列):
|
||||
# 局部变量/self 字段注解不经过 ResolveAnnotationType,故在此显式校验。
|
||||
self._CheckFixedArrayKeyword(Node.annotation)
|
||||
|
||||
@@ -1,60 +1,79 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
class AssertHandle(BaseHandle):
|
||||
def _HandleAssertLlvm(self, Node: ast.Assert) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
cond_val: ir.Value | None = self.HandleExprLlvm(Node.test)
|
||||
if not cond_val:
|
||||
return
|
||||
if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1:
|
||||
zero: ir.Constant = ir.Constant(cond_val.type, 0)
|
||||
cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond")
|
||||
AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail")
|
||||
AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok")
|
||||
Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB)
|
||||
Gen.builder.position_at_start(AssertFailBB)
|
||||
exc_code: int = 9
|
||||
exc_msg: ir.Value | None = None
|
||||
if Node.msg:
|
||||
if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(Node.msg)
|
||||
elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name):
|
||||
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99)
|
||||
if Node.msg.args:
|
||||
first_arg: ast.expr = Node.msg.args[0]
|
||||
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(first_arg)
|
||||
elif isinstance(Node.msg, ast.Name):
|
||||
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99)
|
||||
else:
|
||||
exc_msg = self.HandleExprLlvm(Node.msg)
|
||||
if Gen.eh_except_block_stack:
|
||||
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
|
||||
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
|
||||
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
|
||||
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
|
||||
Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code)
|
||||
if exc_msg:
|
||||
Gen._store(exc_msg, eh_message)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen._store(null_ptr, eh_message)
|
||||
Gen.builder.branch(ExceptBB)
|
||||
else:
|
||||
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||||
if exc_msg:
|
||||
fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string')
|
||||
Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print")
|
||||
else:
|
||||
fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string')
|
||||
Gen.builder.call(printf_func, [fmt], name="assert_fail_print")
|
||||
exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)]))
|
||||
Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit")
|
||||
Gen.builder.unreachable()
|
||||
Gen.builder.position_at_start(AssertOkBB)
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
import vast as ast
|
||||
|
||||
# 无信息 assert 使用的默认 fail_msg;须与 testcheck.check 的 fail_msg: str 形参一致
|
||||
_ASSERT_DEFAULT_FAIL_MSG: str = "assertion failed"
|
||||
# assert 自动依赖的检查库模块名与入口函数(见 includes/testcheck.vp)
|
||||
_ASSERT_CHECK_MODULE: str = "testcheck"
|
||||
_ASSERT_CHECK_FUNC: str = "check"
|
||||
|
||||
class AssertHandle(BaseHandle):
|
||||
def _HandleAssertLlvm(self, Node: ast.Assert) -> None:
|
||||
"""把 `assert 条件[, 信息]` 译为一次普通函数调用 testcheck.check(条件, None, 信息)。
|
||||
|
||||
语义:条件为真 → ok_msg 传 None(静默,不打印 PASS);条件为假 → fail(信息)。
|
||||
不再中止程序(旧实现的 printf AssertionError + exit(1) 已移除),也不再走
|
||||
try/except 抛异常码的路径。
|
||||
"""
|
||||
FailMsgNode: ast.expr = self._ResolveAssertFailMsgNode(Node)
|
||||
CallNode: ast.Call = ast.Call(
|
||||
func=ast.Attribute(
|
||||
value=ast.Name(id=_ASSERT_CHECK_MODULE, ctx=ast.Load()),
|
||||
attr=_ASSERT_CHECK_FUNC,
|
||||
ctx=ast.Load()),
|
||||
args=[Node.test, ast.Constant(value=None, kind=None), FailMsgNode],
|
||||
keywords=[],
|
||||
)
|
||||
ast.copy_location(CallNode, Node)
|
||||
# 复用既有跨模块调用生成路径(含符号解析、实参按形参类型收窄/扩充与 fail-fast 校验)
|
||||
self.HandleExprLlvm(CallNode)
|
||||
|
||||
def _ResolveAssertFailMsgNode(self, Node: ast.Assert) -> ast.expr:
|
||||
"""解析 assert 的信息表达式,并强制其为 str(fail-fast,禁止静默降级)。
|
||||
|
||||
- 无信息 → 字符串字面量 "assertion failed"
|
||||
- 有信息 → 原节点(须为 str 形态:字面量 / f-string / str 变量或属性)
|
||||
"""
|
||||
MsgNode: ast.expr | None = Node.msg
|
||||
if MsgNode is None:
|
||||
DefaultMsg: ast.Constant = ast.Constant(value=_ASSERT_DEFAULT_FAIL_MSG, kind=None)
|
||||
ast.copy_location(DefaultMsg, Node)
|
||||
return DefaultMsg
|
||||
# 旧实现允许把异常类名当信息(映射为异常码、不打印)。check() 的 fail_msg 形参
|
||||
# 是 str,这类写法已无对应语义:显式报错,不静默降级。
|
||||
_ExcName: str | None = None
|
||||
if isinstance(MsgNode, ast.Name):
|
||||
_ExcName = MsgNode.id
|
||||
elif isinstance(MsgNode, ast.Call) and isinstance(MsgNode.func, ast.Name):
|
||||
_ExcName = MsgNode.func.id
|
||||
if _ExcName is not None and _ExcName in EXCEPTION_CODE_MAP:
|
||||
self._RaiseAssertMsgTypeError(
|
||||
f"assert 的信息必须是字符串(str),不能是异常类 '{_ExcName}'")
|
||||
if not self._IsStrAssertMsg(MsgNode):
|
||||
self._RaiseAssertMsgTypeError(
|
||||
"assert 的信息必须是字符串(str):仅支持字符串字面量、f-string 或 str 变量/属性"
|
||||
"(如需拼接请先写入 str 变量)")
|
||||
return MsgNode
|
||||
|
||||
def _IsStrAssertMsg(self, MsgNode: ast.expr) -> bool:
|
||||
"""静态判定 assert 信息是否为 str 形态。
|
||||
|
||||
变量/属性(Name/Attribute)无法在此静态证伪为 str,放行并由调用点的
|
||||
`fail_msg: str` 形参做类型收口;其余非常量、非 f-string 的形态一律拒绝。
|
||||
"""
|
||||
if isinstance(MsgNode, ast.Constant):
|
||||
return isinstance(MsgNode.value, str)
|
||||
if isinstance(MsgNode, ast.JoinedStr):
|
||||
return True
|
||||
if isinstance(MsgNode, (ast.Name, ast.Attribute)):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _RaiseAssertMsgTypeError(self, Message: str) -> None:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
Gen = self.Trans.LlvmGen
|
||||
raise FailFastError(Message + (Gen._get_node_info() if Gen else ''))
|
||||
@@ -16,7 +16,7 @@ from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
|
||||
from lib.core.SymbolUtils import (
|
||||
IsPtrSubscriptNode, IsListAnnotation, IsCPtrMarkerNode,
|
||||
FlattenUnionOperands, IsI8DoublePtrType, IsClassRefPtrAnnotation,
|
||||
FixedArrayKeywordAnnotationError)
|
||||
FixedArrayKeywordAnnotationError, FindAutoAddrMode)
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
|
||||
@@ -1247,6 +1247,11 @@ class BaseHandle:
|
||||
return None
|
||||
VarName: str = item.target.id
|
||||
AnnotationText: str = ast.unparse(item.annotation)
|
||||
# 值引用标记(`&T` / `&temp T`)仅用于函数参数位:结构体字段/成员注解出现即 fail-fast。
|
||||
if FindAutoAddrMode(item.annotation) is not None:
|
||||
raise ValueError(
|
||||
f"[FATAL] 成员 '{VarName}' 的注解 '{AnnotationText}':结构体字段/成员不支持"
|
||||
f"值引用(`&T` / `&temp T`)——值引用仅用于函数参数位,请改用显式指针类型(如 `T*`)")
|
||||
try:
|
||||
TypeInfo: CTypeInfo | None = self.ResolveAnnotationType(item.annotation)
|
||||
except RecursionError:
|
||||
|
||||
@@ -19,11 +19,12 @@ from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
|
||||
# 枚举成员不允许的指针形态名:t.CPtr 家族(CPtr/CNeedPtr/CAutoPtr,后两者继承
|
||||
# CPtr)、内建 rawptr(= t.CPtr)、str/bytes(= i8*)。枚举值是整数常量,
|
||||
# 指针成员语义不成立,命中即明确报错(不静默当 int)。
|
||||
# 枚举成员不允许的指针形态名:t.CPtr 家族(CPtr/CAutoPtr,后者继承
|
||||
# CPtr)、值引用标记(CRef/CTempRef,`&T`/`&temp T`)、内建 rawptr(= t.CPtr)、
|
||||
# str/bytes(= i8*)。枚举值是整数常量,指针成员语义不成立,命中即明确报错
|
||||
# (不静默当 int)。
|
||||
_ENUM_PTR_ANNOTATION_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'CNeedPtr', 'CAutoPtr', 'rawptr', 'str', 'bytes',
|
||||
'CPtr', 'CAutoPtr', 'CRef', 'CTempRef', 'rawptr', 'str', 'bytes',
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,14 @@ _LEN_SUPPORTED_HINT: str = (
|
||||
"或改用 t.CPtr[元素] 并显式维护元素计数"
|
||||
)
|
||||
|
||||
# 已删除的用户可见 CIf 族(c.CIf / c.CIfdef / c.CIfndef / c.CElif / c.CElse / c.CEndif):
|
||||
# 用户再写即在调用点 FailFast,指向原生 cif/celif/celse 与 defined(NAME)(英文报文,
|
||||
# 与 TransPyV CallGenDispatch.vp 同口径)。内部标记 c.@CIf 族不受影响。
|
||||
_REMOVED_CIF_CALL_MSG: str = (
|
||||
"c.CIf / c.CIfdef / c.CIfndef were removed; use the cif / celif / celse statements "
|
||||
"together with the defined(NAME) predicate instead "
|
||||
"(e.g. `cif defined(NAME):` ... `celif ...:` ... `celse:` ...)")
|
||||
|
||||
|
||||
# PROF 热点:_EmitLLVMIRInstruction 对每条 IR 模板都要做多次 re.match / re.split,
|
||||
# 未预编译的模块级入口每次都要「模式串哈希 → re 缓存查找 → 未命中就重新编译」,
|
||||
@@ -938,8 +946,9 @@ class ExprCallHandle(BaseHandle):
|
||||
return self._HandleCDerefAsLlvm(Node)
|
||||
elif FuncAttr == 'PtrToInt':
|
||||
return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
|
||||
elif FuncAttr in ('CIf', 'CElif'):
|
||||
return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node)
|
||||
elif FuncAttr in ('CIf', 'CIfdef', 'CIfndef', 'CElif', 'CElse', 'CEndif'):
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(_REMOVED_CIF_CALL_MSG)
|
||||
elif FuncAttr == 'CError':
|
||||
msg = "compile-time error"
|
||||
if Node.args:
|
||||
@@ -2003,8 +2012,9 @@ class ExprCallHandle(BaseHandle):
|
||||
return self._HandleCDerefAsLlvm(Node)
|
||||
elif func_name == 'PtrToInt':
|
||||
return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
|
||||
elif func_name in ('CIf', 'CElif'):
|
||||
return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node)
|
||||
elif func_name in ('CIf', 'CIfdef', 'CIfndef', 'CElif', 'CElse', 'CEndif'):
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(_REMOVED_CIF_CALL_MSG)
|
||||
elif func_name == 'CError':
|
||||
msg = "compile-time error"
|
||||
if Node.args:
|
||||
@@ -3355,19 +3365,9 @@ class ExprCallHandle(BaseHandle):
|
||||
return self._HandleCDerefAsLlvm(Node)
|
||||
elif MethodName == 'PtrToInt':
|
||||
return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
|
||||
elif MethodName in ('CIf', 'CElif'):
|
||||
if Node.args:
|
||||
ArgVal = self.HandleExprLlvm(Node.args[0])
|
||||
if ArgVal:
|
||||
if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType):
|
||||
return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0)
|
||||
if isinstance(ArgVal.type, ir.IntType):
|
||||
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
|
||||
if isinstance(ArgVal.type, ir.PointerType):
|
||||
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
elif MethodName in ('CIfdef', 'CIfndef'):
|
||||
return ir.Constant(ir.IntType(1), 1)
|
||||
elif MethodName in ('CIf', 'CIfdef', 'CIfndef', 'CElif'):
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(_REMOVED_CIF_CALL_MSG)
|
||||
elif MethodName == 'CError':
|
||||
msg = "compile-time error"
|
||||
if Node.args:
|
||||
@@ -3389,7 +3389,10 @@ class ExprCallHandle(BaseHandle):
|
||||
if _line_offset > 0 and lineno > _line_offset:
|
||||
lineno -= _line_offset
|
||||
raise Exception(f"#error: {msg} (line {lineno})")
|
||||
elif MethodName in ('CElse', 'CEndif', 'CPragma', 'CUndef'):
|
||||
elif MethodName in ('CElse', 'CEndif'):
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(_REMOVED_CIF_CALL_MSG)
|
||||
elif MethodName in ('CPragma', 'CUndef'):
|
||||
return ir.Constant(ir.IntType(1), 1)
|
||||
elif MethodName in ('LLVMIR', 'LInp', 'LOut'):
|
||||
return None
|
||||
|
||||
@@ -10,7 +10,7 @@ import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||||
from lib.core.SymbolUtils import (
|
||||
IsTModule, FindStructNameInAnnotationWithContext, AnnotationContainsName,
|
||||
IsPtrSubscriptNode, DesugarPtrSubscriptToUnion)
|
||||
IsPtrSubscriptNode, DesugarPtrSubscriptToUnion, FindAutoAddrMode)
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
@@ -35,6 +35,21 @@ def _RejectCReturnDecorator(node: ast.AST, decorators: list[ast.AST]) -> None:
|
||||
raise SyntaxError(f"函数 '{func_name}':{_CRETURN_REMOVED_HINT}")
|
||||
|
||||
|
||||
def _RejectRefReturnAnnotation(node: ast.AST) -> None:
|
||||
"""返回注解出现值引用标记(`&T` / `&temp T`)即 fail-fast。
|
||||
|
||||
值引用仅用于函数参数位;返回位一律拒绝,禁止静默按指针降级。
|
||||
"""
|
||||
if getattr(node, 'returns', None) is None:
|
||||
return
|
||||
if FindAutoAddrMode(node.returns) is not None:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
func_name: str = getattr(node, 'name', '<unknown>')
|
||||
raise FailFastError(
|
||||
f"返回注解不支持值引用 `&T` / `&temp T`(函数 '{func_name}'):"
|
||||
f"值引用仅用于函数参数位;返回位请改用显式指针类型(如 `T*`)。")
|
||||
|
||||
|
||||
def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool:
|
||||
"""判断函数返回注解是否为 void 或 extern/export 声明型辅助符号。
|
||||
|
||||
@@ -505,6 +520,7 @@ class FunctionHandle(BaseHandle):
|
||||
FuncName, RawFuncName, func_meta = self._compute_func_name_meta(Node, ClassName)
|
||||
if Node.decorator_list:
|
||||
_RejectCReturnDecorator(Node, Node.decorator_list)
|
||||
_RejectRefReturnAnnotation(Node)
|
||||
MultiRetTypes: list[ast.AST] = []
|
||||
if Node.returns:
|
||||
llvm_attrs: list[str] = self._ExtractLLVMAttrs(Node.returns)
|
||||
@@ -762,16 +778,14 @@ class FunctionHandle(BaseHandle):
|
||||
ParamTypes.append(ParamType)
|
||||
ParamNames.append(Arg.arg)
|
||||
ParamTypeStrs.append(ParamTypeStr)
|
||||
# 检测 t.CNeedPtr / t.CAutoPtr 参数注解
|
||||
auto_mode: str | None = None
|
||||
if ParamTypeStr is not None and hasattr(ParamTypeStr, 'BaseType') and ParamTypeStr.BaseType is not None:
|
||||
if isinstance(ParamTypeStr.BaseType, t.CAutoPtr):
|
||||
auto_mode = 'always'
|
||||
elif isinstance(ParamTypeStr.BaseType, t.CNeedPtr):
|
||||
auto_mode = 'need'
|
||||
# 自动取址模式(由注解读出,不依赖 BaseType 类型):
|
||||
# 'ref' = &T、'temp' = &temp T(合成联合 T | t.CRef / t.CTempRef),
|
||||
# 'always' = t.CAutoPtr。经 Gen._auto_addr_params 供调用点分流。
|
||||
auto_mode: str | None = FindAutoAddrMode(Arg.annotation)
|
||||
auto_addr_modes.append(auto_mode)
|
||||
if self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen):
|
||||
ParamTypeStrs.insert(0, f"struct {ResolvedClassName}")
|
||||
auto_addr_modes.insert(0, None)
|
||||
IsVariadic: bool = Node.args.vararg is not None
|
||||
if extra_params:
|
||||
for var_name, ptr_type in extra_params:
|
||||
@@ -1366,6 +1380,7 @@ class FunctionHandle(BaseHandle):
|
||||
if self._is_generic_function(Node):
|
||||
return
|
||||
FuncName, RawFuncName, func_meta = self._compute_func_name_meta(Node, ClassName)
|
||||
_RejectRefReturnAnnotation(Node)
|
||||
# 保存父级 _CurrentCpythonObjectClass,防止嵌套函数发射污染父方法类上下文
|
||||
# (例如 HandleImport body 内触发 list[ast.ASTptr] 方法发射,结束后会清空 _CurrentCpythonObjectClass)
|
||||
saved_cpython_class: str | None = self.Trans._CurrentCpythonObjectClass
|
||||
@@ -1667,13 +1682,8 @@ class FunctionHandle(BaseHandle):
|
||||
ParamTypes.append(ParamType)
|
||||
ParamNames.append(Arg.arg)
|
||||
ParamTypeStrs.append(ParamTypeInfo)
|
||||
# 检测 t.CNeedPtr / t.CAutoPtr 参数注解
|
||||
auto_mode_emit: str | None = None
|
||||
if ParamTypeInfo is not None and hasattr(ParamTypeInfo, 'BaseType') and ParamTypeInfo.BaseType is not None:
|
||||
if isinstance(ParamTypeInfo.BaseType, t.CAutoPtr):
|
||||
auto_mode_emit = 'always'
|
||||
elif isinstance(ParamTypeInfo.BaseType, t.CNeedPtr):
|
||||
auto_mode_emit = 'need'
|
||||
# 自动取址模式(由注解读出):'ref' = &T、'temp' = &temp T、'always' = t.CAutoPtr
|
||||
auto_mode_emit: str | None = FindAutoAddrMode(Arg.annotation)
|
||||
auto_addr_modes_emit.append(auto_mode_emit)
|
||||
Gen._record_var_signedness(Arg.arg, ParamIsUnsigned)
|
||||
self.Trans.VarScopes[-1][Arg.arg] = ParamTypeInfo
|
||||
@@ -1706,7 +1716,8 @@ class FunctionHandle(BaseHandle):
|
||||
self.Trans.CurrentMultiRetTypes = MultiRetTypes
|
||||
else:
|
||||
self.Trans.CurrentMultiRetTypes = None
|
||||
self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen)
|
||||
if self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen):
|
||||
auto_addr_modes_emit.insert(0, None)
|
||||
IsVariadic = Node.args.vararg is not None
|
||||
if extra_params:
|
||||
for var_name, ptr_type in extra_params:
|
||||
|
||||
@@ -23,12 +23,16 @@ class IfHandle(BaseHandle):
|
||||
return None
|
||||
|
||||
def _is_cif_call(self, node: ast.expr) -> bool:
|
||||
"""判定 If.test 是否为 cif/celif 的内部标记调用(c.@CIf 族,解析期合成)。
|
||||
|
||||
标记属性名带前导 '@'(词法器不可产出),故用户写的 c.CIf(...) 不会命中。
|
||||
"""
|
||||
if isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
|
||||
return node.func.attr in ('CIf', 'CIfdef', 'CIfndef')
|
||||
return node.func.attr in ('@CIf', '@CIfdef', '@CIfndef')
|
||||
if isinstance(node.func, ast.Name):
|
||||
return node.func.id in ('CIf', 'CIfdef', 'CIfndef')
|
||||
return node.func.id in ('@CIf', '@CIfdef', '@CIfndef')
|
||||
return False
|
||||
|
||||
def _resolve_macro_name(self, arg: ast.expr) -> str | None:
|
||||
@@ -55,17 +59,17 @@ class IfHandle(BaseHandle):
|
||||
kind = node.func.id
|
||||
else:
|
||||
return None
|
||||
if kind == 'CIfdef':
|
||||
if kind == '@CIfdef':
|
||||
name: str | None = self._resolve_macro_name(args[0])
|
||||
if name is None:
|
||||
return 0
|
||||
return 1 if self._is_macro_defined(name) else 0
|
||||
elif kind == 'CIfndef':
|
||||
elif kind == '@CIfndef':
|
||||
name: str | None = self._resolve_macro_name(args[0])
|
||||
if name is None:
|
||||
return 1
|
||||
return 0 if self._is_macro_defined(name) else 1
|
||||
elif kind == 'CIf':
|
||||
elif kind == '@CIf':
|
||||
return self._eval_const_expr(args[0])
|
||||
return None
|
||||
|
||||
@@ -154,19 +158,36 @@ class IfHandle(BaseHandle):
|
||||
return 1 if result != 0.0 else 0
|
||||
return result
|
||||
|
||||
def _CifExprText(self, node: ast.expr) -> str:
|
||||
"""cif/celif 标记调用内层条件表达式的源码文本(供 FailFast 报文,失败取占位)。"""
|
||||
try:
|
||||
if isinstance(node, ast.Call) and node.args:
|
||||
return ast.unparse(node.args[0])
|
||||
return ast.unparse(node)
|
||||
except Exception:
|
||||
return '<condition>'
|
||||
|
||||
def _HandleIfLlvm(self, Node: ast.If) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if self._is_cif_call(Node.test):
|
||||
compile_time_val: int | None = self._evaluate_cif_condition(Node.test)
|
||||
if compile_time_val is not None:
|
||||
if compile_time_val:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
elif Node.orelse:
|
||||
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
|
||||
self._HandleIfLlvm(Node.orelse[0])
|
||||
else:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
return
|
||||
if compile_time_val is None:
|
||||
# cif/celif 条件必须是编译期常量:求不出 ⇒ FailFast(不再回退运行时分支)。
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
expr_text: str = self._CifExprText(Node.test)
|
||||
Message: str = (
|
||||
f"'cif' / 'celif' condition is not a compile-time constant: {expr_text}. "
|
||||
f"Only CDefine constants, literals, their arithmetic/comparison/boolean/"
|
||||
f"bitwise operators and the 'defined(NAME)' predicate are allowed.")
|
||||
raise FailFastError(Message + (Gen._get_node_info() if Gen else ''))
|
||||
if compile_time_val:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
elif Node.orelse:
|
||||
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
|
||||
self._HandleIfLlvm(Node.orelse[0])
|
||||
else:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
return
|
||||
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
|
||||
if not Cond:
|
||||
return
|
||||
|
||||
@@ -14,7 +14,7 @@ from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName, FindStructNameInAnnotationWithContext
|
||||
from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName, FindStructNameInAnnotationWithContext, FindAutoAddrMode
|
||||
from lib.core.SymbolUtils import EnumClassIntWidth, ExpandSoftKeywords
|
||||
from lib.core.SymbolUtils import ClassHasFuncLevelCVTable, IsVtableSlotMethod
|
||||
|
||||
@@ -1870,6 +1870,13 @@ class ImportHandle(BaseHandle):
|
||||
func = Gen._get_or_declare_function(MangledName, FuncType)
|
||||
Gen.functions[MangledName] = func
|
||||
Gen.functions[FuncName] = func
|
||||
# 跨模块自动取址模式登记(ref/temp/always):调用点 Gen._apply_auto_addr 按函数名
|
||||
# 查表,命中才做取址适配。ParamTypes 与 Node.args.args 逐位对齐(含方法 self)。
|
||||
_auto_modes: list[str | None] = [
|
||||
FindAutoAddrMode(a.annotation) for a in Node.args.args]
|
||||
if any(m is not None for m in _auto_modes):
|
||||
Gen._auto_addr_params[MangledName] = _auto_modes
|
||||
Gen._auto_addr_params[FuncName] = _auto_modes
|
||||
func_meta = FuncMeta.NONE
|
||||
if Node.decorator_list:
|
||||
for d in Node.decorator_list:
|
||||
|
||||
@@ -207,6 +207,13 @@ class HandlesTypeMerge(BaseHandle):
|
||||
return Info
|
||||
|
||||
if ModulePath == 't' or (ModulePath and ModulePath.startswith('t.')):
|
||||
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):与
|
||||
# t.CPtr 同形的「一层指针」,使 `T | t.CRef` 合并为 T*(pointer 层 +1)。
|
||||
if TypeName in ('CRef', 'CTempRef'):
|
||||
Info = CTypeInfo()
|
||||
Info.PtrCount = 1
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
if self._IsTModuleType(TypeName):
|
||||
TypeClass = CTypeHelper.GetTModuleCType(TypeName) or getattr(t, TypeName, None)
|
||||
if TypeClass == t.CArrayPtr:
|
||||
|
||||
@@ -378,8 +378,9 @@ class BaseGenMixin:
|
||||
# 编译期 with 上下文栈:记录当前嵌套 with 链中所有可用的 provides 字段名
|
||||
# 用于 __require_must__ 的纯编译期静态可达性检查
|
||||
self._with_provides_stack: list[list[str]] = []
|
||||
# 函数参数自动取地址模式: func_name -> [None, None, 'need', 'always', ...]
|
||||
# 'need': t.CNeedPtr — 仅对非指针值取地址
|
||||
# 函数参数自动取地址模式: func_name -> [None, None, 'ref', 'temp', 'always', ...]
|
||||
# 'ref': &T — 实参非指针左值取址,右值 fail-fast
|
||||
# 'temp': &temp T — 实参非指针时在调用方建同型临时再取址
|
||||
# 'always': t.CAutoPtr — 无条件取地址
|
||||
self._auto_addr_params: dict[str, list[str | None]] = {}
|
||||
self.global_struct_class: dict[str, str] = {}
|
||||
|
||||
@@ -94,11 +94,17 @@ class FuncGenMixin:
|
||||
self.class_methods[ClassName].append(MethodName)
|
||||
|
||||
def _apply_auto_addr(self, func_name: str, args: list[ir.Value]) -> list[ir.Value]:
|
||||
"""对函数参数应用自动取地址逻辑(t.CNeedPtr / t.CAutoPtr)。
|
||||
|
||||
在调用前对标记为 auto-addr 的参数自动取地址:
|
||||
- 'need' (t.CNeedPtr): 仅对非指针值取地址(alloca + store + get pointer)
|
||||
- 'always' (t.CAutoPtr): 无条件取地址
|
||||
"""对函数参数应用自动取址逻辑(ref / temp / always 三种模式)。
|
||||
|
||||
在调用前对标记为 auto-addr 的实参做地址适配(模式由 HandlesFunctions 从形参注解
|
||||
读出并写入 Gen._auto_addr_params[func_name]):
|
||||
- 'ref'(&T):实参已是指针 → 原样传;非指针左值 → 传该左值地址;
|
||||
非指针且非左值(字面量/表达式结果)→ fail-fast(禁止静默降级)。
|
||||
- 'temp'(&temp T):实参已是指针 → 原样传;否则在 entry 块建同型临时 + store + 传地址。
|
||||
- 'always'(t.CAutoPtr):无条件取址(保持既有语义)。
|
||||
|
||||
非指针左值的地址取自实参 load 指令的指针操作数(`load(p)` ⇒ p 即左值地址),
|
||||
因为调用点实参已按 rvalue 求值(标量变量的 load 结果)。
|
||||
"""
|
||||
modes: list[str | None] | None = self._auto_addr_params.get(func_name)
|
||||
if not modes:
|
||||
@@ -109,8 +115,23 @@ class FuncGenMixin:
|
||||
continue
|
||||
arg: ir.Value = new_args[i]
|
||||
is_ptr: bool = isinstance(arg.type, ir.PointerType)
|
||||
if mode == 'always' or (mode == 'need' and not is_ptr):
|
||||
# alloca + store + get pointer
|
||||
if mode == 'ref':
|
||||
if is_ptr:
|
||||
continue
|
||||
if isinstance(arg, ir.LoadInstr) and len(arg.operands) == 1:
|
||||
# load(p) 的 p 即该左值的地址(该实参是变量/字段/下标的取值)
|
||||
new_args[i] = arg.operands[0]
|
||||
continue
|
||||
raise FailFastError(
|
||||
f"&T 形参只接受左值,右值请用具名临时变量或改用 &temp T"
|
||||
f"(调用 {func_name} 第 {i} 个实参类型 {arg.type})")
|
||||
if mode == 'temp':
|
||||
if is_ptr:
|
||||
continue
|
||||
slot: ir.Value = self._allocaEntry(arg.type, name=f"autoaddr_tmp_{i}")
|
||||
self.builder.store(arg, slot)
|
||||
new_args[i] = slot
|
||||
elif mode == 'always':
|
||||
slot: ir.Value = self.builder.alloca(arg.type)
|
||||
self.builder.store(arg, slot)
|
||||
new_args[i] = slot
|
||||
|
||||
@@ -2386,6 +2386,38 @@ def IsCPtrNode(node: ast.AST) -> bool:
|
||||
and node.attr == 'CPtr')
|
||||
|
||||
|
||||
# 值引用参数标记名 → 自动取址模式(仅注解 AST 内按名字识别,非真实类):
|
||||
# 'CRef' → 'ref' (&T :实参非指针左值取址,右值 fail-fast)
|
||||
# 'CTempRef' → 'temp' (&temp T :实参非指针时在调用方建同型临时再取址)
|
||||
# 'CAutoPtr' → 'always' (t.CAutoPtr:无条件取址,保持既有语义)
|
||||
_AUTO_ADDR_MARKER_MODES: dict[str, str] = {
|
||||
'CRef': 'ref', 'CTempRef': 'temp', 'CAutoPtr': 'always',
|
||||
}
|
||||
|
||||
|
||||
def FindAutoAddrMode(node: ast.AST | None) -> str | None:
|
||||
"""注解 AST 内查找自动取址模式标记,返回 'ref' / 'temp' / 'always';无则 None。
|
||||
|
||||
只按名字识别(Attribute.attr 或 Name.id),递归联合/嵌套注解;CRef/CTempRef
|
||||
非真实类,不出现在 lib/includes/t.py。
|
||||
"""
|
||||
if node is None:
|
||||
return None
|
||||
if isinstance(node, ast.Attribute):
|
||||
mode = _AUTO_ADDR_MARKER_MODES.get(node.attr)
|
||||
if mode is not None:
|
||||
return mode
|
||||
elif isinstance(node, ast.Name):
|
||||
mode = _AUTO_ADDR_MARKER_MODES.get(node.id)
|
||||
if mode is not None:
|
||||
return mode
|
||||
for child in ast.iter_child_nodes(node):
|
||||
mode = FindAutoAddrMode(child)
|
||||
if mode is not None:
|
||||
return mode
|
||||
return None
|
||||
|
||||
|
||||
def IsCPtrSubscriptNode(node: ast.AST) -> bool:
|
||||
"""检查节点是否为 t.CPtr[T] 下标指针类型(非裸标记,裸标记见 IsCPtrNode)。
|
||||
|
||||
|
||||
@@ -1131,6 +1131,14 @@ class TypeAnnotationResolver:
|
||||
ModulePath = resolved_name
|
||||
|
||||
if ModulePath and IsTModulePath(ModulePath):
|
||||
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`):非真实类,仅按名字
|
||||
# 识别为「一层指针」(与 t.CPtr 同形),使联合形态 `T | t.CRef` 解析为 T*、
|
||||
# `void | t.CRef` 解析为 void*(i8*)。模式语义(ref/temp)由注解侧识别。
|
||||
if TypeName in ('CRef', 'CTempRef'):
|
||||
Info: CTypeInfo = CTypeInfo()
|
||||
Info.PtrCount = 1
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
TypeClass: type | None = CTypeHelper.GetTModuleCType(TypeName)
|
||||
if TypeClass is None:
|
||||
TypeClass = getattr(t, TypeName, None)
|
||||
|
||||
@@ -454,32 +454,6 @@ class CDefine:
|
||||
return []
|
||||
|
||||
|
||||
class CIfndef:
|
||||
"""#ifndef 条件编译"""
|
||||
def __init__(self, condition: Any) -> None:
|
||||
self.condition: Any = condition
|
||||
|
||||
@staticmethod
|
||||
def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]:
|
||||
"""处理 c.CIfndef() 调用"""
|
||||
if args:
|
||||
condition: Any = translator.HandleExpr(args[0])[0]
|
||||
return ['#ifndef ' + _to_str(condition)]
|
||||
return ['#if 0']
|
||||
|
||||
class CIfdef:
|
||||
"""#ifdef 条件编译"""
|
||||
def __init__(self, condition: Any) -> None:
|
||||
self.condition: Any = condition
|
||||
|
||||
@staticmethod
|
||||
def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]:
|
||||
"""处理 c.CIfdef() 调用"""
|
||||
if args:
|
||||
condition: Any = translator.HandleExpr(args[0])[0]
|
||||
return ['#ifdef ' + _to_str(condition)]
|
||||
return ['#if 0']
|
||||
|
||||
class CError:
|
||||
"""#error 错误信息"""
|
||||
def __init__(self, condition: Any) -> None:
|
||||
@@ -536,20 +510,6 @@ class TokenPast:
|
||||
return ['']
|
||||
|
||||
|
||||
class CIf:
|
||||
"""#if 条件编译"""
|
||||
def __init__(self, condition: Any) -> None:
|
||||
self.condition: Any = condition
|
||||
|
||||
@staticmethod
|
||||
def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]:
|
||||
"""处理 c.CIf() 调用"""
|
||||
if args:
|
||||
condition: Any = translator.HandleExpr(args[0])[0]
|
||||
return ['#if ' + _to_str(condition)]
|
||||
return ['#if 0']
|
||||
|
||||
|
||||
class CElif:
|
||||
"""#elif 条件编译"""
|
||||
def __init__(self, condition: Any) -> None:
|
||||
@@ -688,9 +648,6 @@ Library_C = {
|
||||
'AsmInp': AsmInp,
|
||||
'AsmOut': AsmOut,
|
||||
'CDefine': CDefine,
|
||||
'CIfndef': CIfndef,
|
||||
'CIfdef': CIfdef,
|
||||
'CIf': CIf,
|
||||
'CElif': CElif,
|
||||
'CElse': CElse,
|
||||
'CEndif': CEndif,
|
||||
|
||||
@@ -530,15 +530,6 @@ class CPtr(CType, Generic[T]):
|
||||
def __init__(self, value: Any = None) -> None:
|
||||
super().__init__(value)
|
||||
|
||||
class CNeedPtr(CPtr):
|
||||
"""函数签名注解:自动取地址(仅对非指针值)。
|
||||
用作参数类型时,编译器在调用处自动将非指针值取地址为指针。
|
||||
若参数已经是指针,则不做操作。"""
|
||||
position: ClassVar[frozenset[str]] = frozenset({CType.POINTER})
|
||||
auto_addr_mode: ClassVar[str] = 'need'
|
||||
def __init__(self, value: Any = None) -> None:
|
||||
super().__init__(value)
|
||||
|
||||
class CAutoPtr(CPtr):
|
||||
"""函数签名注解:无条件取地址。
|
||||
用作参数类型时,编译器在调用处无条件将值取地址为指针,
|
||||
|
||||
+90
-1
@@ -40,6 +40,12 @@ def _JoinConstParts(parts: list[object]) -> str | bytes:
|
||||
|
||||
_HEX_ALPHABET: str = '0123456789abcdefABCDEF'
|
||||
|
||||
# 已删除的用户可见 CIf 族名:用户再写 c.CIf / c.CIfdef / c.CIfndef ⇒ FailFast,
|
||||
# 提示改用原生 cif/celif/celse 与 defined() 谓词(内部标记由解析期合成,不走此处)。
|
||||
_REMOVED_CIF_NAMES: frozenset[str] = frozenset({
|
||||
'CIf', 'CIfdef', 'CIfndef', 'c.CIf', 'c.CIfdef', 'c.CIfndef',
|
||||
})
|
||||
|
||||
|
||||
def _HexValOf(ch: str) -> int:
|
||||
"""单个字符的十六进制位值;非十六进制字符返回 0(与 C 解析器 vast_c.HexVal 同口径)。"""
|
||||
@@ -581,6 +587,44 @@ class ExprParserMixin(TokenStream):
|
||||
self._ExpectOp(')')
|
||||
node: N.Call = N.Call(func=func, args=args, keywords=keywords)
|
||||
self._FixLoc(node, start)
|
||||
return self._DesugarSpecialCall(node, start)
|
||||
|
||||
def _CallCalleeName(self, func: N.expr) -> str:
|
||||
"""被调用者的限定名:Name('X')→'X';Attribute(c,'X')→'c.X';否则空串。"""
|
||||
if isinstance(func, N.Name):
|
||||
return func.id
|
||||
if isinstance(func, N.Attribute) and isinstance(func.value, N.Name):
|
||||
return f'{func.value.id}.{func.attr}'
|
||||
return ''
|
||||
|
||||
def _DesugarSpecialCall(self, node: N.Call, start: Token) -> N.expr:
|
||||
"""调用点的特殊 desugar / fail-fast。
|
||||
|
||||
- `defined(NAME)`:仅 cif/celif 条件内合法(`self._InCIfCond`),
|
||||
desugar 为内部标记调用 `c.CIfdef(NAME)`;其余位置 FailFast。
|
||||
- `c.CIf` / `c.CIfdef` / `c.CIfndef`(及裸名):已删除,FailFast 指向新语法。
|
||||
"""
|
||||
callee: str = self._CallCalleeName(node.func)
|
||||
if callee in _REMOVED_CIF_NAMES:
|
||||
raise SyntaxError(
|
||||
f"'{callee}(...)' has been removed; use the native 'cif' / 'celif' / "
|
||||
f"'celse' statements together with the 'defined(NAME)' predicate "
|
||||
f"instead, at line {start.Line}")
|
||||
if callee == 'defined':
|
||||
if not self._InCIfCond:
|
||||
raise SyntaxError(
|
||||
"'defined(NAME)' is only allowed inside a 'cif' / 'celif' "
|
||||
f"condition, at line {start.Line}")
|
||||
if len(node.args) != 1 or node.keywords:
|
||||
raise SyntaxError(
|
||||
f"'defined' expects exactly one macro name (e.g. defined(MAX_SIZE)), "
|
||||
f"at line {start.Line}")
|
||||
marker: N.Call = N.Call(
|
||||
func=N.Attribute(value=N.Name(id='c', ctx=N.Load()),
|
||||
attr='@CIfdef', ctx=N.Load()),
|
||||
args=[node.args[0]], keywords=[])
|
||||
self._FixLoc(marker, start)
|
||||
return marker
|
||||
return node
|
||||
|
||||
def _ParseSubscriptTail(self, value: N.expr, start: Token) -> N.Subscript:
|
||||
@@ -1567,7 +1611,33 @@ class ExprParserMixin(TokenStream):
|
||||
正确写法示例),绝不静默丢弃:注解末尾若仍遗留未被 `_AtPtrSuffix` 接受的
|
||||
'*'/'**'(如 `a: int * 2` / `a: int* | t.CPtr`),判据拒绝消费即终止编译
|
||||
(历史事故:静默退化会产出错误的指针层数)。
|
||||
|
||||
值引用参数注解(仅形参位有效):前导 `&` 为 ref 模式、`&temp` 为 temp 模式,
|
||||
合成联合形态 `T | t.CRef` / `T | t.CTempRef` 承载(CRef/CTempRef 非真实类,
|
||||
仅按名字识别;语义侧见 HandlesFunctions / FuncGen)。表达式位的 `&x` 不受影响。
|
||||
"""
|
||||
ref_mode: str | None = None
|
||||
ref_tok: Token = self._Peek()
|
||||
if self._AtOp('&'):
|
||||
self._Next()
|
||||
if self._AtName('temp'):
|
||||
self._Next()
|
||||
ref_mode = 'temp'
|
||||
else:
|
||||
ref_mode = 'ref'
|
||||
# `&` / `&temp` 之后必须紧跟类型;缺失即响亮失败(禁止静默丢弃)
|
||||
end_tok: Token = self._Peek()
|
||||
if end_tok.Type in (NEWLINE, NL, ENDMARKER) or (
|
||||
end_tok.Type == OP and end_tok.Value in (')', ',', ':', '=', ']', '}', ';')):
|
||||
snippet: str = ''
|
||||
try:
|
||||
snippet = (self.Source.splitlines()[end_tok.Line - 1] or '').strip()
|
||||
except Exception:
|
||||
snippet = ''
|
||||
raise SyntaxError(
|
||||
f"[vast] 值引用参数注解缺少类型:第 {end_tok.Line} 行第 {end_tok.Col} 列的 "
|
||||
f"`&` 后必须紧跟类型 T(ref:`&T`;temp:`&temp T`)。"
|
||||
f"源码片段 {snippet!r}。正确示例:`def f(p: &int)` / `def f(p: &temp void)`。")
|
||||
saved_flag: bool = self._InTypeAnnotation
|
||||
self._InTypeAnnotation = True
|
||||
try:
|
||||
@@ -1575,9 +1645,13 @@ class ExprParserMixin(TokenStream):
|
||||
finally:
|
||||
self._InTypeAnnotation = saved_flag
|
||||
if expr is None:
|
||||
if ref_mode is not None:
|
||||
raise SyntaxError(
|
||||
"[vast] 值引用参数注解缺少类型:`&` 后必须紧跟类型 T"
|
||||
"(ref:`&T`;temp:`&temp T`)。")
|
||||
return None
|
||||
if self._AtPtrSuffix(expr):
|
||||
return self._ConsumePtrSuffix(expr)
|
||||
expr = self._ConsumePtrSuffix(expr)
|
||||
tok: Token = self._Peek()
|
||||
if tok.Type == OP and tok.Value in ('*', '**'):
|
||||
snippet: str = ''
|
||||
@@ -1595,8 +1669,23 @@ class ExprParserMixin(TokenStream):
|
||||
f"正确示例:`a: t.CPtr*` / `a: rawptr*` / `a: t.X**` / "
|
||||
f"`a: rawptr[ast.AST*]` / `def f(p: int*) -> int**`。"
|
||||
)
|
||||
if ref_mode is not None:
|
||||
expr = self._MakeRefMarker(expr, ref_mode, ref_tok)
|
||||
return expr
|
||||
|
||||
def _MakeRefMarker(self, base: N.expr, mode: str, tok: Token) -> N.expr:
|
||||
"""构造值引用标记联合:`base | t.CRef`(ref)/ `base | t.CTempRef`(temp)。
|
||||
|
||||
CRef / CTempRef 非真实类,仅作为注解 AST 内的名字标记(语义侧按名字识别)。
|
||||
"""
|
||||
marker: N.expr = N.Attribute(
|
||||
value=N.Name(id='t', ctx=N.Load()),
|
||||
attr='CRef' if mode == 'ref' else 'CTempRef',
|
||||
ctx=N.Load())
|
||||
node: N.BinOp = N.BinOp(left=base, op=N.BitOr(), right=marker)
|
||||
self._FixLoc(node, tok)
|
||||
return node
|
||||
|
||||
# 类型结束后缀:'_AtPtrSuffix' 的判据表
|
||||
# - 全局(任意表达式上下文):'*'/'**' 串后紧跟这些 operator 时,乘法/幂本就缺右操作数
|
||||
# (即原语法错误),故按指针后缀处理不会改变任何合法表达式的语义;
|
||||
|
||||
@@ -91,6 +91,32 @@ _SWITCH_KEYWORD: str = 'switch'
|
||||
# 标记调用(switch 生成侧据此让 case 体不自动跳出 switch,落到下一个 case)。
|
||||
_FALLTHROUGH_KEYWORD: str = 'fallthrough'
|
||||
|
||||
# ======================================================================
|
||||
# cif / celif / celse 编译期条件编译(软关键字)
|
||||
# ======================================================================
|
||||
# 语法:`cif <编译期常量表达式>:` / `celif <...>:` / `celse:`
|
||||
# 语义:只有 cif 能开链;celif/celse 必须属于同一条 cif 链。
|
||||
# 解析期 desugar 为既有「If + CIf 族标记调用」形状(与 Viper 侧口径一致):
|
||||
# cif E: → If(test=c.@CIf(E), body, orelse)
|
||||
# celif E: → 同链下一个 If(test=c.@CIf(E), ...)(挂在上一支 orelse)
|
||||
# celse: → 普通 orelse
|
||||
# defined(N) → c.@CIfdef(N) 标记调用
|
||||
# 标记(c.@CIf / c.@CIfdef)是内部表示:用户写 c.CIf(...) 在 ExprParser 处报错。
|
||||
_CIF_KEYWORD: str = 'cif'
|
||||
_CELIF_KEYWORD: str = 'celif'
|
||||
_CELSE_KEYWORD: str = 'celse'
|
||||
# 内部 CIf 族标记:desugar 产出的调用名(用户不可写)。
|
||||
# 与 Viper 侧解析器(includes/ast/parser.vp 的 _MakeCifMarker)同拼写:属性名带前导 '@',
|
||||
# 词法器无法产出该拼写,故用户写的 c.CIf(...) 永远不会命中此标记(会被 ExprParser 拒绝)。
|
||||
_CIF_MARKER: str = '@CIf'
|
||||
_CIFDEF_MARKER: str = '@CIfdef'
|
||||
# cif 语句起始判定:语句起始 NAME('cif') 后紧跟这些运算符时按普通语句(赋值/注解)
|
||||
# 处理,避免 `cif = 5` / `cif: int = 5` 被误判为 cif 语句。
|
||||
_CIF_NON_STATEMENT_OPS: frozenset[str] = frozenset({
|
||||
'=', ':', '+=', '-=', '*=', '/=', '//=', '%=', '**=',
|
||||
'<<=', '>>=', '&=', '|=', '^=', '@=',
|
||||
})
|
||||
|
||||
|
||||
class Parser(ExprParserMixin):
|
||||
"""Viper/Python 完整语法分析器。"""
|
||||
@@ -101,6 +127,10 @@ class Parser(ExprParserMixin):
|
||||
# "virtual def / novirtual def 只能直接写在类体内"。
|
||||
_InClassBody: bool = False
|
||||
|
||||
# _InCIfCond:当前是否正在解析 cif/celif 的条件表达式。用于判定 `defined(NAME)`
|
||||
# 谓词的合法位置(仅 cif/celif 条件内合法,其余位置 FailFast)。
|
||||
_InCIfCond: bool = False
|
||||
|
||||
# ==================================================================
|
||||
# 模块级入口
|
||||
# ==================================================================
|
||||
@@ -177,6 +207,15 @@ class Parser(ExprParserMixin):
|
||||
# struct 纯数据类型定义(硬关键字):语句起始一律按 struct 定义解析。
|
||||
if v == _STRUCT_KEYWORD:
|
||||
return self._ParseStructDef()
|
||||
# cif 编译期条件编译(软关键字):语句起始 + 非赋值/注解形态。
|
||||
if v == _CIF_KEYWORD and self._IsCIfStatementStart():
|
||||
return self._ParseCIf()
|
||||
# celif / celse 必须属于某条 cif 链(由 _ParseCIf 直接消费);
|
||||
# 语句起始独立出现 ⇒ FailFast。
|
||||
if v == _CELIF_KEYWORD or v == _CELSE_KEYWORD:
|
||||
raise SyntaxError(
|
||||
f"'{v}' must belong to a 'cif' chain (no matching 'cif') "
|
||||
f"at line {tok.Line}")
|
||||
if v == 'if':
|
||||
return self._ParseIf()
|
||||
if v == 'while':
|
||||
@@ -1215,6 +1254,88 @@ class Parser(ExprParserMixin):
|
||||
self._FixLoc(node, start)
|
||||
return node
|
||||
|
||||
# ==================================================================
|
||||
# cif / celif / celse 编译期条件编译(软关键字,desugar 到 c.CIf 标记)
|
||||
# ==================================================================
|
||||
def _IsCIfStatementStart(self) -> bool:
|
||||
"""语句起始 NAME('cif') 是否按 cif 语句解析。
|
||||
|
||||
排除赋值/注解形态(`cif = 5` / `cif: int = 5` / `cif += 1`):
|
||||
第二种 token 为 '=' ':' 或增强赋值运算符时按普通语句处理。
|
||||
"""
|
||||
nxt: Token = self._Peek(1)
|
||||
if nxt.Type == OP and nxt.Value in _CIF_NON_STATEMENT_OPS:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _MakeCIfMarkerCall(self, attr: str, expr: N.expr, start: Token) -> N.Call:
|
||||
"""构造内部标记调用 `c.<attr>(expr)`(用户不可写;cif/defined 的 desugar)。"""
|
||||
func: N.Attribute = N.Attribute(
|
||||
value=N.Name(id='c', ctx=N.Load()), attr=attr, ctx=N.Load())
|
||||
self._FixLoc(func, start)
|
||||
call: N.Call = N.Call(func=func, args=[expr], keywords=[])
|
||||
self._FixLoc(call, start)
|
||||
return call
|
||||
|
||||
def _ParseCIf(self) -> N.If:
|
||||
"""`cif <expr>:`(+ 可选 celif/celse 链)。"""
|
||||
start: Token = self._Next() # cif
|
||||
test: N.expr = self._ParseCIfCondition()
|
||||
self._ExpectOp(':')
|
||||
body: list[N.stmt] = self._ParseSuite()
|
||||
orelse: list[N.stmt] = self._ParseCIfChainTail()
|
||||
node: N.If = N.If(test=self._MakeCIfMarkerCall(_CIF_MARKER, test, start),
|
||||
body=body, orelse=orelse)
|
||||
self._FixLoc(node, start)
|
||||
return node
|
||||
|
||||
def _ParseCIfCondition(self) -> N.expr:
|
||||
"""解析 cif/celif 条件表达式,期间允许 `defined(NAME)` 谓词。"""
|
||||
prev: bool = self._InCIfCond
|
||||
self._InCIfCond = True
|
||||
try:
|
||||
return self.ParseExpr()
|
||||
finally:
|
||||
self._InCIfCond = prev
|
||||
|
||||
def _ParseCIfChainTail(self) -> list[N.stmt]:
|
||||
"""解析 cif 链尾部(celif/celse),返回 orelse 列表。
|
||||
|
||||
- 无 celif/celse:返回空(cif 链正常收尾)。
|
||||
- 出现普通 elif/else:FailFast(cif 链必须以 celse 收尾)。
|
||||
"""
|
||||
if self._AtName(_CELIF_KEYWORD):
|
||||
return [self._ParseCelif()]
|
||||
if self._AtName(_CELSE_KEYWORD):
|
||||
self._Next() # celse
|
||||
self._ExpectOp(':')
|
||||
body: list[N.stmt] = self._ParseSuite()
|
||||
# celse 之后不得再出现 celif / celse(同缩进层级会落在本方法可见处)。
|
||||
if self._AtName(_CELIF_KEYWORD) or self._AtName(_CELSE_KEYWORD):
|
||||
bad_tok: Token = self._Peek()
|
||||
raise SyntaxError(
|
||||
f"'{bad_tok.Value}' cannot follow 'celse' (the 'celse' branch must be "
|
||||
f"the last of the 'cif' chain) at line {bad_tok.Line}")
|
||||
return body
|
||||
if self._AtName('elif') or self._AtName('else'):
|
||||
kind: str = self._Peek().Value
|
||||
raise SyntaxError(
|
||||
f"a 'cif' chain must be closed with 'celse', not '{kind}', "
|
||||
f"at line {self._Peek().Line}")
|
||||
return []
|
||||
|
||||
def _ParseCelif(self) -> N.If:
|
||||
"""`celif <expr>:`(cif 链的后续分支)。"""
|
||||
start: Token = self._Next() # celif
|
||||
test: N.expr = self._ParseCIfCondition()
|
||||
self._ExpectOp(':')
|
||||
body: list[N.stmt] = self._ParseSuite()
|
||||
orelse: list[N.stmt] = self._ParseCIfChainTail()
|
||||
node: N.If = N.If(test=self._MakeCIfMarkerCall(_CIF_MARKER, test, start),
|
||||
body=body, orelse=orelse)
|
||||
self._FixLoc(node, start)
|
||||
return node
|
||||
|
||||
def _ParseWhile(self) -> N.While:
|
||||
start: Token = self._Next() # while
|
||||
test: N.expr = self.ParseExpr()
|
||||
|
||||
Binary file not shown.
+424
-5
@@ -101,6 +101,7 @@ typedef struct {
|
||||
int FStringExprEnd; /* f-string 表达式段结束位置(body 内偏移) */
|
||||
int InTypeAnnotation; /* 类型注解模式:'*'/'**' 允许按 C 风格指针后缀判定 */
|
||||
int InClassBody; /* 当前套件的直接拥有者是否为 ClassDef(virtual def 判据) */
|
||||
int InCIfCond; /* 是否正在解析 cif/celif 条件(defined(NAME) 合法位置判据) */
|
||||
Token *PtrSuffixTail; /* 最近消费的 C 指针后缀尾 token(识别 (T*)x 无括号强转) */
|
||||
} Parser;
|
||||
|
||||
@@ -2652,6 +2653,8 @@ static PyObject *ConsumePtrSuffix(Parser *P, PyObject *Node) {
|
||||
}
|
||||
|
||||
static PyObject *ParseCallTail(Parser *P, PyObject *Func, Token *Start);
|
||||
static PyObject *DesugarSpecialCall(Parser *P, PyObject *Node, Token *Start);
|
||||
static PyObject *MakeCifMarkerCall(Parser *P, const char *AttrName, PyObject *Expr, Token *Start);
|
||||
|
||||
/* 判定当前位置的 '*'/'**' 串是否为 `T*(x)` 形式的指针后缀**强转调用**
|
||||
* (对齐 Python ExprParser._AtPtrSuffixCall):
|
||||
@@ -2709,13 +2712,64 @@ static PyObject *ConsumePtrSuffixCall(Parser *P, PyObject *Base, Token *Start) {
|
||||
return Call;
|
||||
}
|
||||
|
||||
/* 类型注解入口:置注解模式标志(对齐 Python ExprParser._ParseTypeAnnotation)。 */
|
||||
/* 类型注解入口:置注解模式标志(对齐 Python ExprParser._ParseTypeAnnotation)。
|
||||
*
|
||||
* 值引用参数注解(仅形参位有效,对齐纯 Python 端):
|
||||
* 前导 '&' + 可选名 'temp',合成联合形态 base | t.CRef(ref)/ base | t.CTempRef(temp)。
|
||||
* CRef/CTempRef 非真实类,仅作注解 AST 内的名字标记(语义侧按名字识别)。
|
||||
* '&'/'&temp' 之后缺类型(行尾 / ')' / ',' / ':' / '=' / ']' / '}' / ';')时响亮失败。 */
|
||||
static PyObject *ParseTypeAnnotation(Parser *P) {
|
||||
int RefTemp = 0; /* 0=非值引用 1=ref 2=temp */
|
||||
Token *RefTok = PeekTok(P, 0);
|
||||
if (AtOp(P, "&")) {
|
||||
NextTok(P);
|
||||
if (AtName(P, "temp")) {
|
||||
NextTok(P);
|
||||
RefTemp = 2;
|
||||
} else {
|
||||
RefTemp = 1;
|
||||
}
|
||||
Token *End = PeekTok(P, 0);
|
||||
if (End->Kind == TK_NEWLINE || End->Kind == TK_NL
|
||||
|| End->Kind == TK_ENDMARKER
|
||||
|| TokIsOp(End, ")") || TokIsOp(End, ",") || TokIsOp(End, ":")
|
||||
|| TokIsOp(End, "=") || TokIsOp(End, "]") || TokIsOp(End, "}")
|
||||
|| TokIsOp(End, ";")) {
|
||||
SyntaxErrorAt(P, End,
|
||||
"值引用参数注解缺少类型:`&` 后必须紧跟类型 T(ref:`&T`;temp:`&temp T`)");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
int Saved = P->InTypeAnnotation;
|
||||
P->InTypeAnnotation = 1;
|
||||
PyObject *Node = ParseExpr(P);
|
||||
P->InTypeAnnotation = Saved;
|
||||
return Node;
|
||||
if (Node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (RefTemp == 0) {
|
||||
return Node;
|
||||
}
|
||||
PyObject *Marker = MakeTAttrNode(P, RefTemp == 2 ? "CTempRef" : "CRef");
|
||||
if (Marker == NULL) {
|
||||
Py_DECREF(Node);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Op = MakeSingleton(P, "BitOr");
|
||||
if (Op == NULL) {
|
||||
Py_DECREF(Node);
|
||||
Py_DECREF(Marker);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Argv[3] = { Node, Op, Marker };
|
||||
PyObject *Wrap = NewNode(P, "BinOp", Argv, 3);
|
||||
Py_DECREF(Op);
|
||||
Py_DECREF(Marker);
|
||||
Py_DECREF(Node);
|
||||
if (Wrap != NULL) {
|
||||
FixLoc(P, Wrap, RefTok);
|
||||
}
|
||||
return Wrap;
|
||||
}
|
||||
|
||||
/* term:factor (*|/|//|%|@ factor)* */
|
||||
@@ -3008,10 +3062,127 @@ static PyObject *ParseCallTail(Parser *P, PyObject *Func, Token *Start) {
|
||||
Py_DECREF(Keywords);
|
||||
if (Node != NULL) {
|
||||
FixLoc(P, Node, Start);
|
||||
Node = DesugarSpecialCall(P, Node, Start);
|
||||
}
|
||||
return Node;
|
||||
}
|
||||
|
||||
/* 被调用者限定名:Name('X')→'X';Attribute(Name('c'),'X')→'c.X';否则 NULL(无异常)。 */
|
||||
static PyObject *MakeCifMarkerCall(Parser *P, const char *AttrName, PyObject *Expr, Token *Start);
|
||||
static PyObject *CalleeQualName(PyObject *Func) {
|
||||
if (NodeIs(Func, "Name")) {
|
||||
return PyObject_GetAttrString(Func, "id");
|
||||
}
|
||||
if (NodeIs(Func, "Attribute")) {
|
||||
PyObject *Value = PyObject_GetAttrString(Func, "value");
|
||||
PyObject *Attr = PyObject_GetAttrString(Func, "attr");
|
||||
PyObject *Result = NULL;
|
||||
if (Value != NULL && Attr != NULL && NodeIs(Value, "Name")) {
|
||||
PyObject *Id = PyObject_GetAttrString(Value, "id");
|
||||
if (Id != NULL) {
|
||||
Result = PyUnicode_FromFormat("%U.%U", Id, Attr);
|
||||
Py_DECREF(Id);
|
||||
}
|
||||
}
|
||||
Py_XDECREF(Value);
|
||||
Py_XDECREF(Attr);
|
||||
return Result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int StrIsOneOf(PyObject *S, const char *const *Names) {
|
||||
for (int I = 0; Names[I] != NULL; I++) {
|
||||
if (PyUnicode_CompareWithASCIIString(S, Names[I]) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 调用点特殊 desugar / fail-fast:接管 Node 的引用,返回新引用(失败返回 NULL)。
|
||||
* - defined(NAME):仅 cif/celif 条件内合法(P->InCIfCond)⇒ desugar 为 c.@CIfdef(NAME);
|
||||
* 其余位置 ⇒ FailFast。
|
||||
* - c.CIf / c.CIfdef / c.CIfndef(及裸名):已删除 ⇒ FailFast,指向原生新语法。 */
|
||||
static PyObject *DesugarSpecialCall(Parser *P, PyObject *Node, Token *Start) {
|
||||
PyObject *Func = PyObject_GetAttrString(Node, "func");
|
||||
if (Func == NULL) {
|
||||
PyErr_Clear();
|
||||
return Node;
|
||||
}
|
||||
/* 廉价预筛:只看标识符短名(Name.id / Attribute.attr),与 cif 无关的调用一律
|
||||
* 立即返回,避免在解析热路径上为每个调用构造限定名并分配字符串。 */
|
||||
PyObject *Short = NULL;
|
||||
if (NodeIs(Func, "Name")) {
|
||||
Short = PyObject_GetAttrString(Func, "id");
|
||||
} else if (NodeIs(Func, "Attribute")) {
|
||||
Short = PyObject_GetAttrString(Func, "attr");
|
||||
}
|
||||
if (Short == NULL) {
|
||||
PyErr_Clear();
|
||||
Py_DECREF(Func);
|
||||
return Node;
|
||||
}
|
||||
static const char *Interesting[] = {"CIf", "CIfdef", "CIfndef", "defined", NULL};
|
||||
int Hit = StrIsOneOf(Short, Interesting);
|
||||
Py_DECREF(Short);
|
||||
if (!Hit) {
|
||||
Py_DECREF(Func);
|
||||
return Node;
|
||||
}
|
||||
PyObject *Callee = CalleeQualName(Func);
|
||||
Py_DECREF(Func);
|
||||
if (Callee == NULL) {
|
||||
PyErr_Clear();
|
||||
return Node;
|
||||
}
|
||||
static const char *Removed[] = {
|
||||
"CIf", "CIfdef", "CIfndef", "c.CIf", "c.CIfdef", "c.CIfndef", NULL
|
||||
};
|
||||
if (StrIsOneOf(Callee, Removed)) {
|
||||
PyErr_Format(PyExc_SyntaxError,
|
||||
"'%U(...)' has been removed; use the native 'cif' / 'celif' / 'celse' "
|
||||
"statements together with the 'defined(NAME)' predicate instead, at line %d",
|
||||
Callee, Start->Line);
|
||||
Py_DECREF(Callee);
|
||||
Py_DECREF(Node);
|
||||
return NULL;
|
||||
}
|
||||
if (PyUnicode_CompareWithASCIIString(Callee, "defined") == 0) {
|
||||
Py_DECREF(Callee);
|
||||
if (!P->InCIfCond) {
|
||||
PyErr_Format(PyExc_SyntaxError,
|
||||
"'defined(NAME)' is only allowed inside a 'cif' / 'celif' condition, at line %d",
|
||||
Start->Line);
|
||||
Py_DECREF(Node);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Args = PyObject_GetAttrString(Node, "args");
|
||||
PyObject *Kw = PyObject_GetAttrString(Node, "keywords");
|
||||
PyObject *Arg0 = NULL;
|
||||
if (Args != NULL && Kw != NULL && PyList_Check(Args) && PyList_Check(Kw)
|
||||
&& PyList_GET_SIZE(Args) == 1 && PyList_GET_SIZE(Kw) == 0) {
|
||||
Arg0 = PyList_GetItem(Args, 0); /* borrowed */
|
||||
}
|
||||
if (Arg0 == NULL) {
|
||||
PyErr_Format(PyExc_SyntaxError,
|
||||
"'defined' expects exactly one macro name (e.g. defined(MAX_SIZE)), at line %d",
|
||||
Start->Line);
|
||||
Py_XDECREF(Args);
|
||||
Py_XDECREF(Kw);
|
||||
Py_DECREF(Node);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Marker = MakeCifMarkerCall(P, "@CIfdef", Arg0, Start);
|
||||
Py_XDECREF(Args);
|
||||
Py_XDECREF(Kw);
|
||||
Py_DECREF(Node);
|
||||
return Marker;
|
||||
}
|
||||
Py_DECREF(Callee);
|
||||
return Node;
|
||||
}
|
||||
|
||||
static PyObject *ParseSliceList(Parser *P);
|
||||
static PyObject *ParseSliceItem(Parser *P);
|
||||
|
||||
@@ -4324,6 +4495,12 @@ static PyObject *ParseSimpleStmt(Parser *P);
|
||||
static PyObject *ParseSuite(Parser *P);
|
||||
static PyObject *ParseSuiteOwned(Parser *P, int OwnerIsClass);
|
||||
static PyObject *ParseIf(Parser *P);
|
||||
static PyObject *ParseCIf(Parser *P);
|
||||
static PyObject *ParseCelif(Parser *P);
|
||||
static PyObject *ParseCIfChainTail(Parser *P);
|
||||
static PyObject *MakeCifMarkerCall(Parser *P, const char *AttrName, PyObject *Expr, Token *Start);
|
||||
static int IsCIfStatementStart(Parser *P);
|
||||
static PyObject *DesugarSpecialCall(Parser *P, PyObject *Node, Token *Start);
|
||||
static PyObject *ParseWhile(Parser *P);
|
||||
static PyObject *ParseFor(Parser *P, int IsAsync);
|
||||
static PyObject *ParseTry(Parser *P);
|
||||
@@ -4437,6 +4614,22 @@ static PyObject *ParseStatement(Parser *P) {
|
||||
if (TokIsName(T, "struct")) {
|
||||
return ParseStructDef(P, NULL);
|
||||
}
|
||||
/* cif 编译期条件编译(软关键字):语句起始 + 非赋值/注解形态 */
|
||||
if (TokIsName(T, "cif") && IsCIfStatementStart(P)) {
|
||||
return ParseCIf(P);
|
||||
}
|
||||
/* celif / celse 必须属于某条 cif 链(由 ParseCIf 直接消费);
|
||||
* 语句起始独立出现 ⇒ FailFast */
|
||||
if (TokIsName(T, "celif")) {
|
||||
SyntaxErrorAt(P, T,
|
||||
"'celif' must belong to a 'cif' chain (no matching 'cif')");
|
||||
return NULL;
|
||||
}
|
||||
if (TokIsName(T, "celse")) {
|
||||
SyntaxErrorAt(P, T,
|
||||
"'celse' must belong to a 'cif' chain (no matching 'cif')");
|
||||
return NULL;
|
||||
}
|
||||
if (TokIsName(T, "if")) {
|
||||
return ParseIf(P);
|
||||
}
|
||||
@@ -6023,6 +6216,227 @@ static PyObject *ParseIf(Parser *P) {
|
||||
return Node;
|
||||
}
|
||||
|
||||
/* ===================== cif / celif / celse 编译期条件编译 =====================
|
||||
* 软关键字:语句起始 NAME('cif') 后非赋值/注解形态 ⇒ cif 语句。
|
||||
* 解析期 desugar 为既有「If + c.@CIf 标记调用」形状(与纯 Python / Viper 侧一致):
|
||||
* cif E: → If(test=c.@CIf(E), body, orelse)
|
||||
* celif E: → 同链下一个 If(test=c.@CIf(E), ...)(挂在上一支 orelse)
|
||||
* celse: → 普通 orelse
|
||||
* 标记 c.@CIf / c.@CIfdef 由本解析器合成(属性名前导 '@' 词法器不可产出),
|
||||
* 用户写 c.CIf 在表达式处 FailFast。 */
|
||||
|
||||
/* cif 语句起始判定:第二 token 为 '=' ':' 或增强赋值 ⇒ 非 cif 语句(cif = 5)。 */
|
||||
static int IsCIfStatementStart(Parser *P) {
|
||||
Token *N = PeekTok(P, 1);
|
||||
if (N->Kind != TK_OP) {
|
||||
return 1;
|
||||
}
|
||||
static const char *Ops[] = {
|
||||
"=", ":", "+=", "-=", "*=", "/=", "//=", "%=", "**=",
|
||||
"<<=", ">>=", "&=", "|=", "^=", "@=", NULL
|
||||
};
|
||||
for (int I = 0; Ops[I] != NULL; I++) {
|
||||
if (TokIsOp(N, Ops[I])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 构造内部标记调用 `c.<AttrName>(Expr)`(用户不可写)。 */
|
||||
static PyObject *MakeCifMarkerCall(Parser *P, const char *AttrName, PyObject *Expr, Token *Start) {
|
||||
PyObject *Load1 = MakeCtx(P, "Load");
|
||||
PyObject *IdC = Load1 ? PyUnicode_FromString("c") : NULL;
|
||||
if (Load1 == NULL || IdC == NULL) {
|
||||
Py_XDECREF(Load1);
|
||||
Py_XDECREF(IdC);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *NameArgv[2] = { IdC, Load1 };
|
||||
PyObject *NameNode = NewNode(P, "Name", NameArgv, 2);
|
||||
Py_DECREF(IdC);
|
||||
Py_DECREF(Load1);
|
||||
if (NameNode == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
FixLoc(P, NameNode, Start);
|
||||
PyObject *Load2 = MakeCtx(P, "Load");
|
||||
PyObject *AttrStr = Load2 ? PyUnicode_FromString(AttrName) : NULL;
|
||||
if (Load2 == NULL || AttrStr == NULL) {
|
||||
Py_XDECREF(Load2);
|
||||
Py_XDECREF(AttrStr);
|
||||
Py_DECREF(NameNode);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *AttrArgv[3] = { NameNode, AttrStr, Load2 };
|
||||
PyObject *AttrNode = NewNode(P, "Attribute", AttrArgv, 3);
|
||||
Py_DECREF(AttrStr);
|
||||
Py_DECREF(Load2);
|
||||
Py_DECREF(NameNode);
|
||||
if (AttrNode == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
FixLoc(P, AttrNode, Start);
|
||||
PyObject *Args = NewList();
|
||||
PyObject *Kw = NewList();
|
||||
if (Args == NULL || Kw == NULL) {
|
||||
Py_XDECREF(Args);
|
||||
Py_XDECREF(Kw);
|
||||
Py_DECREF(AttrNode);
|
||||
return NULL;
|
||||
}
|
||||
PyList_Append(Args, Expr);
|
||||
PyObject *CallArgv[3] = { AttrNode, Args, Kw };
|
||||
PyObject *CallNode = NewNode(P, "Call", CallArgv, 3);
|
||||
Py_DECREF(Args);
|
||||
Py_DECREF(Kw);
|
||||
Py_DECREF(AttrNode);
|
||||
if (CallNode == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
FixLoc(P, CallNode, Start);
|
||||
return CallNode;
|
||||
}
|
||||
|
||||
/* 解析 cif/celif 条件表达式:期间允许 defined(NAME) 谓词。 */
|
||||
static PyObject *ParseCIfCondition(Parser *P) {
|
||||
int Prev = P->InCIfCond;
|
||||
P->InCIfCond = 1;
|
||||
PyObject *E = ParseExpr(P);
|
||||
P->InCIfCond = Prev;
|
||||
return E;
|
||||
}
|
||||
|
||||
/* `cif <expr>:` + 可选 celif/celse 链 */
|
||||
static PyObject *ParseCIf(Parser *P) {
|
||||
Token *Start = NextTok(P); /* cif */
|
||||
PyObject *Test = ParseCIfCondition(P);
|
||||
if (Test == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!ExpectOp(P, ":")) {
|
||||
Py_DECREF(Test);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Body = ParseSuite(P);
|
||||
if (Body == NULL) {
|
||||
Py_DECREF(Test);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Marker = MakeCifMarkerCall(P, "@CIf", Test, Start);
|
||||
Py_DECREF(Test);
|
||||
if (Marker == NULL) {
|
||||
Py_DECREF(Body);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Orelse = ParseCIfChainTail(P);
|
||||
if (Orelse == NULL) {
|
||||
Py_DECREF(Marker);
|
||||
Py_DECREF(Body);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Argv[3] = { Marker, Body, Orelse };
|
||||
PyObject *Node = NewNode(P, "If", Argv, 3);
|
||||
Py_DECREF(Marker);
|
||||
Py_DECREF(Body);
|
||||
Py_DECREF(Orelse);
|
||||
if (Node != NULL) {
|
||||
FixLoc(P, Node, Start);
|
||||
}
|
||||
return Node;
|
||||
}
|
||||
|
||||
/* `celif <expr>:`(cif 链的后续分支) */
|
||||
static PyObject *ParseCelif(Parser *P) {
|
||||
Token *Start = NextTok(P); /* celif */
|
||||
PyObject *Test = ParseCIfCondition(P);
|
||||
if (Test == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!ExpectOp(P, ":")) {
|
||||
Py_DECREF(Test);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Body = ParseSuite(P);
|
||||
if (Body == NULL) {
|
||||
Py_DECREF(Test);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Marker = MakeCifMarkerCall(P, "@CIf", Test, Start);
|
||||
Py_DECREF(Test);
|
||||
if (Marker == NULL) {
|
||||
Py_DECREF(Body);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Orelse = ParseCIfChainTail(P);
|
||||
if (Orelse == NULL) {
|
||||
Py_DECREF(Marker);
|
||||
Py_DECREF(Body);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Argv[3] = { Marker, Body, Orelse };
|
||||
PyObject *Node = NewNode(P, "If", Argv, 3);
|
||||
Py_DECREF(Marker);
|
||||
Py_DECREF(Body);
|
||||
Py_DECREF(Orelse);
|
||||
if (Node != NULL) {
|
||||
FixLoc(P, Node, Start);
|
||||
}
|
||||
return Node;
|
||||
}
|
||||
|
||||
/* cif 链尾部(celif/celse)→ orelse 列表;错配 ⇒ FailFast(静态报文)。 */
|
||||
static PyObject *ParseCIfChainTail(Parser *P) {
|
||||
if (AtName(P, "celif")) {
|
||||
PyObject *Nested = ParseCelif(P);
|
||||
if (Nested == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *L = NewList();
|
||||
if (L == NULL) {
|
||||
Py_DECREF(Nested);
|
||||
return NULL;
|
||||
}
|
||||
PyList_Append(L, Nested);
|
||||
Py_DECREF(Nested);
|
||||
return L;
|
||||
}
|
||||
if (AtName(P, "celse")) {
|
||||
NextTok(P);
|
||||
if (!ExpectOp(P, ":")) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *Body = ParseSuite(P);
|
||||
if (Body == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (AtName(P, "celif")) {
|
||||
SyntaxErrorAt(P, PeekTok(P, 0),
|
||||
"'celif' cannot follow 'celse' (the 'celse' branch must be the last of the 'cif' chain)");
|
||||
Py_DECREF(Body);
|
||||
return NULL;
|
||||
}
|
||||
if (AtName(P, "celse")) {
|
||||
SyntaxErrorAt(P, PeekTok(P, 0),
|
||||
"'celse' cannot follow 'celse' (the 'celse' branch must be the last of the 'cif' chain)");
|
||||
Py_DECREF(Body);
|
||||
return NULL;
|
||||
}
|
||||
return Body;
|
||||
}
|
||||
if (AtName(P, "elif")) {
|
||||
SyntaxErrorAt(P, PeekTok(P, 0),
|
||||
"a 'cif' chain must be closed with 'celse', not 'elif'");
|
||||
return NULL;
|
||||
}
|
||||
if (AtName(P, "else")) {
|
||||
SyntaxErrorAt(P, PeekTok(P, 0),
|
||||
"a 'cif' chain must be closed with 'celse', not 'else'");
|
||||
return NULL;
|
||||
}
|
||||
return NewList();
|
||||
}
|
||||
|
||||
/* while / else */
|
||||
static PyObject *ParseWhile(Parser *P) {
|
||||
Token *Start = NextTok(P); /* while */
|
||||
@@ -7265,15 +7679,16 @@ static PyObject *VastC_Parse(PyObject *Self, PyObject *Args, PyObject *Kwargs) {
|
||||
P.FStringExprEnd = 0;
|
||||
P.InTypeAnnotation = 0;
|
||||
P.InClassBody = 0;
|
||||
P.InCIfCond = 0;
|
||||
P.PtrSuffixTail = NULL;
|
||||
PyObject *Tree = ParseModule(&P);
|
||||
PyMem_Free(Tokens);
|
||||
PyMem_Free(LineStarts);
|
||||
if (Tree == NULL) {
|
||||
if (P.Error) {
|
||||
/* 报错必须自足可定位:带上 类型名 + token 原文 + 行号,措辞与
|
||||
* Python ExprParser 的 `unexpected token OP('*') at line N` 一致,
|
||||
* 这样 `[vast] C 解析器失败,回退纯 Python:<文件>: …` 一行即可定位。 */
|
||||
* 这样 `[vast] C 解析器失败,回退纯 Python:<文件>: …` 一行即可定位。
|
||||
* 注意:P.ErrTok 指向 Tokens 数组内部,必须在 PyMem_Free 之前读取
|
||||
* (否则读到 free 链表指针,首个 token 会被写成 ENDMARKER(''))。 */
|
||||
char TokBuf[64];
|
||||
const char *TokName = "ENDMARKER";
|
||||
TokBuf[0] = '\0';
|
||||
@@ -7296,8 +7711,12 @@ static PyObject *VastC_Parse(PyObject *Self, PyObject *Args, PyObject *Kwargs) {
|
||||
P.ErrMsg ? P.ErrMsg : "vast_c: syntax error",
|
||||
TokName, TokBuf, P.ErrLine);
|
||||
}
|
||||
PyMem_Free(Tokens);
|
||||
PyMem_Free(LineStarts);
|
||||
return NULL;
|
||||
}
|
||||
PyMem_Free(Tokens);
|
||||
PyMem_Free(LineStarts);
|
||||
if (strcmp(Mode, "exec") == 0) {
|
||||
return Tree;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user