diff --git a/App/lib/core/Gen/GenApi.vp b/App/lib/core/Gen/GenApi.vp index 9cd7854..b607654 100644 --- a/App/lib/core/Gen/GenApi.vp +++ b/App/lib/core/Gen/GenApi.vp @@ -899,6 +899,13 @@ def translate_import(trans: HT.Translator*, node: ast.AST*) -> int: return 0 +# ---------------- translate_cif_imports (delegates to ImportsGenMixin.translate_cif_imports) ---------------- +def translate_cif_imports(trans: HT.Translator*, node: ast.AST*) -> int: + """Delegate to gen.translate_cif_imports (module-level cif conditional imports)""" + if _g_gen is not None: return _g_gen.ImportsGen.translate_cif_imports(trans, node) + return 0 + + # ---------------- translate_import_from_module (delegates to ImportsGenMixin.translate_import_from_module) ---------------- def translate_import_from_module(trans: HT.Translator*, node: ast.AST*) -> int: """Delegate to gen.translate_import_from_module""" diff --git a/App/lib/core/Gen/ImportsGenMixin.vp b/App/lib/core/Gen/ImportsGenMixin.vp index 4408f3d..dec614a 100644 --- a/App/lib/core/Gen/ImportsGenMixin.vp +++ b/App/lib/core/Gen/ImportsGenMixin.vp @@ -690,6 +690,43 @@ novirtual class ImportsGenMixin: if trans.ModuleSha1 is not None: self.register_reexport(trans.ModuleSha1, local_name, fi_target) return 0 + # translate_cif_imports - 模块级 cif 条件 import 的预扫描。 + # cif/celif/celse 在编译期求值,只有**选中分支**里的 Import/ImportFrom 会进入 + # _imported_modules/_from_imports;未选中分支的模块不进入依赖闭包,也不会被编译/链接, + # 因此可以安全地用 cif 在平台专有模块之间二选一。普通模块级 if 不受理(原样忽略)。 + def translate_cif_imports(self, trans: HT.Translator*, node: ast.AST*) -> int: + """Collect the taken branch's imports from a module-level cif; returns how many were registered.""" + if trans is None or node is None or node.kind() != ast.ASTKind.If: return 0 + ifn: ast.If* = ast.If*(node) + if ifn is None or ifn.test is None: return 0 + if self.Gen.StmtGenCif._is_cif_call(ifn.test) == 0: return 0 + taken: int = self.Gen.StmtGenCif._prune_cif_test(trans.Pool, trans, ifn.test) + if taken != 0: return self._collect_cif_imports_in(trans, ifn.children) + return self._collect_cif_imports_in(trans, ifn.orelse) + + # _collect_cif_imports_in - 递归收集一个分支体内的 import。 + # celif 的 orelse 是嵌套 If(条件仍需按 cif 求值),celse 的 orelse 是普通语句列表; + # 其余语句(define/函数/赋值)在模块级 import 预扫描阶段一律跳过。 + def _collect_cif_imports_in(self, trans: HT.Translator*, stmts: list[ast.AST*]*) -> int: + """Walk one cif branch body: register imports, recurse into nested celif chains.""" + if stmts is None: return 0 + n: int = 0 + cnt: sizet = len(stmts) + for i in range(int(cnt)): + st: ast.AST* = stmts.get(i) + if st is None: continue + k: int = st.kind() + if k == ast.ASTKind.Import: + self.translate_import(trans, st) + n += 1 + elif k == ast.ASTKind.ImportFrom: + self.translate_import_from_module(trans, st) + self.translate_import_from_names(trans, st) + n += 1 + elif k == ast.ASTKind.If: + n += self.translate_cif_imports(trans, st) + return n + def InitImportsGen(self) -> int: """Initialize the ImportsGen fields, called by Generator at construction.""" if self is None: return 1 diff --git a/App/lib/core/Gen/Translator.vp b/App/lib/core/Gen/Translator.vp index 6745799..b753892 100644 --- a/App/lib/core/Gen/Translator.vp +++ b/App/lib/core/Gen/Translator.vp @@ -30,7 +30,7 @@ define MAX_VARS = 1024 # Function-table capacity (single source of truth). Allocation happens in _init_state; # the registration-side max_count passed to add_func_to_table must be <= this capacity. define MAX_FUNCS = 1024 -# Reference convention: cross-module t.CDefine is readable only inside functions, so write +# Reference convention: cross-module t.DefineT is readable only inside functions, so write # qualified names there; the global/nonlocal name-table capacity must match on both guard sides. define MAX_GLOBAL_NAMES = 128 # Coroutine table capacity (VPC-M1): async function count / coroutine var and local-name count @@ -208,6 +208,11 @@ novirtual class Translator: # Chain-nonlocal heap built flag (built once per function): reset to 0 on entering a function, # set to 1 by _prepare_chain_nonlocals. Shared by nested definitions to avoid double malloc. _nl_chain_done: int + # 每个 chain nonlocal 名字是否**已经**迁移到堆(0/1,与 _nl_chain_names 同下标)。 + # 迁移不止发生一次:函数体开头先整体扫一遍(必须早于任何语句,否则先交出去的 + # `&local` 会指向栈副本),之后再遇到嵌套 def 时只补扫新名字 —— 靠这张表跳过的已迁移项, + # 避免同一个对象被二次搬走(那会让上一次交出去的地址再次失效)。 + _nl_migrated: rawptr # Generic specialization context: type parameter and argument name lists of the class # currently being specialized. Set by _specialize_generic_class; None when not specializing. @@ -217,6 +222,11 @@ novirtual class Translator: # Phase 1a declare mode: 1=register struct/enum/union only (no body), 0=full translation _declare_only: int + # Expression-statement context: 1 = the surrounding statement discards the call result + # (e.g. a bare `VLogger.error(...)` line). A placeholder return type is then harmless, + # so cross-module return-type resolution must not fail-fast in this context. + _discard_result: int + # App pre-registration (Phase A-pre) switch: when 1, imports and LoadDepVpiIntoModule run even # if _declare_only != 0, keeping class field annotations in phase A's context. App-only. _pre_allow_dep_inject: int @@ -264,6 +274,7 @@ novirtual class Translator: self._nl_chain_names = None self._nl_chain_count = 0 self._nl_chain_done = 0 + self._nl_migrated = None self.GenericTypeParamNames = None self.GenericTypeArgs = None self._declare_only = 0 @@ -522,13 +533,17 @@ novirtual class Translator: cur_imp_lineno = child.lineno GenApi.translate_import_from_module(self, child) GenApi.translate_import_from_names(self, child) + elif kd == ast.ASTKind.If: + # 模块级 cif 条件 import:按平台常量只收集选中分支(未选中分支的模块 + # 不进依赖闭包,因此不会被编译/链接);普通 if 由 collect 函数自行忽略。 + GenApi.translate_cif_imports(self, child) # Mirror TPC _inject_auto_imports: detect list/dict container usage (bare annotations, # constructors, subscripts) and mark the container classes visible so bare names resolve. self._inject_auto_container_visibility(pool, tree) # A module using `assert` behaves as if it had `import testcheck`: inject the module # before dependency-vpi loading so testcheck.check resolves across modules. self._inject_auto_assert_import(pool, tree) - # CTypedef declarations are registered by Phase1 text scanning (AST string tokens are unstable). + # TypedefT declarations are registered by Phase1 text scanning (AST string tokens are unstable). # Cross-module .vpi injection loads dep .vpi declares when full-translating or during App pre-registration. if self._imported_modules is not None: # Error-context frame: import site that triggered dependency stub loading @@ -598,6 +613,15 @@ novirtual class Translator: if tk == ast.ASTKind.Attribute: at: ast.Attribute* = ast.Attribute*(target) if at is None or at.value is None: return 0 + # Nested form `proj.advanced. = ...`: erase the whole statement as well. + if at.value.kind() == ast.ASTKind.Attribute: + mid: ast.Attribute* = ast.Attribute*(at.value) + if mid is None or mid.value is None: return 0 + if mid.value.kind() != ast.ASTKind.Name: return 0 + mn: ast.Name* = ast.Name*(mid.value) + if mn is None or mn.id is None: return 0 + if self._vb_in_proj_vars(mn.id, proj_vars) != 0: return 1 + return 0 if at.value.kind() != ast.ASTKind.Name: return 0 bn: ast.Name* = ast.Name*(at.value) if bn is None or bn.id is None: return 0 @@ -609,15 +633,6 @@ novirtual class Translator: if value is None or value.kind() != ast.ASTKind.Call: return 0 cl: ast.Call* = ast.Call*(value) if cl is None or cl.func is None: return 0 - # Nested form `proj.advanced. = ...`: erase the whole statement as well. - if at.value.kind() == ast.ASTKind.Attribute: - mid: ast.Attribute* = ast.Attribute*(at.value) - if mid is None or mid.value is None: return 0 - if mid.value.kind() != ast.ASTKind.Name: return 0 - mn: ast.Name* = ast.Name*(mid.value) - if mn is None or mn.id is None: return 0 - if self._vb_in_proj_vars(mn.id, proj_vars) != 0: return 1 - return 0 if cl.func.kind() != ast.ASTKind.Attribute: return 0 at: ast.Attribute* = ast.Attribute*(cl.func) if at is None or at.attr is None or at.value is None: return 0 diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index 10739b0..72035bd 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -60,6 +60,11 @@ novirtual class TranslatorGenMixin: elif kd == ast.ASTKind.ImportFrom: self.Gen.ImportsGen.translate_import_from_module(trans, child) self.Gen.ImportsGen.translate_import_from_names(trans, child) + elif kd == ast.ASTKind.If: + # 模块级 cif 条件 import:只在 import-scan / declare 模式下补收集 + # (_declare_only == 0 时 _translate_module_level 的预扫描已经收过,重复会写出 + # 重复的 from_imports 条目)。 + if trans._declare_only != 0: self.Gen.ImportsGen.translate_cif_imports(trans, child) elif kd == ast.ASTKind.FunctionDef: # PEP 695 generic functions (def f[T]): skip at the definition site (the # template is registered by Phase1Scan/Phase2) and monomorphize at call sites.