diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index 2122ce0..10739b0 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -1,4 +1,5 @@ import lib.core.Gen.Generator as Generator +import lib.core.builtin.ViperBuild as ViperBuild from stdint import * import ast import mlirlite @@ -20,20 +21,20 @@ import lib.core.Gen.GenApi as GenApi novirtual class TranslatorGenMixin: """Translation driver Mixin.""" - # _register_cexport_from_funcdef - Phase 1a: pre-register every CExport/State function + # _register_cexport_from_funcdef - Phase 1a: pre-register every ExportT/State function # name in the global table so Phase 1b's alphabetical order cannot miss bare-name calls. Gen: Generator.Generator* def _register_cexport_from_funcdef(self, trans: HT.Translator*, node: ast.AST*) -> int: - """Pre-register CExport/State function names into the global table (no IR).""" + """Pre-register ExportT/State function names into the global table (no IR).""" fd: ast.FunctionDef* = ast.FunctionDef*(node) if fd is None or fd.name is None: return 0 if trans is None or trans.ModuleSha1 is None: return 0 - # Check whether the return type carries a CExport or State marker + # Check whether the return type carries a ExportT or State marker has_export: int = 0 has_state: int = 0 if fd.returns is not None: - has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport", 0) + has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "ExportT", 0) has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0) if has_export != 0 or has_state != 0: self.Gen.CallGenBase.register_cexport_func(trans.ModuleSha1, fd.name) @@ -64,7 +65,7 @@ novirtual class TranslatorGenMixin: # template is registered by Phase1Scan/Phase2) and monomorphize at call sites. fd_tc: ast.FunctionDef* = ast.FunctionDef*(child) if fd_tc is not None and fd_tc.type_params is not None: continue - # Phase 1a declare mode registers only CExport/State names; Phase 1b fully translates bodies. + # Phase 1a declare mode registers only ExportT/State names; Phase 1b fully translates bodies. if trans._declare_only == 0: # 函数体翻译 = 编译器下潜进一个源码上下文:推一帧(def 位置), # 让函数体内部的错误在 traceback 里回溯到"正在翻译哪个函数"(调用链)。 @@ -91,14 +92,16 @@ novirtual class TranslatorGenMixin: added = self.Gen.StmtGen.translate_stmt(trans, child) added_total += added elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2: - # Module-level AnnAssign: skip in import-scan mode, handle only CDefine in + # Module-level AnnAssign: skip in import-scan mode, handle only DefineT in # struct-registration mode, and handle all in full-translation mode. added = self.handle_module_level_var(trans, child) added_total += added elif trans._declare_only == 0 and kd == ast.ASTKind.Assign: - # Module-level Assign without a builder -> create a global (full-translation mode only) - added = self.handle_module_level_var(trans, child) - added_total += added + # ffilib.CDLL(...) 是纯编译期配置(Pass 0 已抽取),不能生成模块级全局 + asn_ml: ast.Assign* = ast.Assign*(child) + if asn_ml is None or ViperBuild.IsCdlLDeclCall(asn_ml.value) == 0: + added = self.handle_module_level_var(trans, child) + added_total += added return added_total @@ -127,13 +130,13 @@ novirtual class TranslatorGenMixin: if ag is not None and ag.annotation is not None: self.Gen.TypeGenResolve.resolve_annotation_type(pool, ag.annotation, imp, fi, trans, 0) # _build_array_initializer_text - build an LLVM IR array initializer from an AST List, - # formatted as [N x elem_ty] [elem_ty val0, ...], for module-level t.CArray literals. + # formatted as [N x elem_ty] [elem_ty val0, ...], for module-level t.ArrayT literals. def _build_array_initializer_text(self, pool: memhub.MemBuddy*, var_ty: mlirlite.LLVMType*, list_node: ast.List*) -> str: """Build LLVM IR array initializer text from an AST List node; None on failure.""" if var_ty is None or list_node is None: return None # Re-cast so the VPC compiler recognizes ast.List, avoiding type inference degrading - # to t.CPtr when init_list_node's initial value is None. + # to rawptr when init_list_node's initial value is None. ln: ast.List* = ast.List*(list_node) if ln is None: return None @@ -274,7 +277,7 @@ novirtual class TranslatorGenMixin: return buf # _build_string_array_initializer_text - initialize a char array global from a string literal: - # t.CArray[char, N] = "..." -> [i8 b0, ..., i8 0, ...] zero-padded; empty -> zeroinitializer. + # t.ArrayT[char, N] = "..." -> [i8 b0, ..., i8 0, ...] zero-padded; empty -> zeroinitializer. def _build_string_array_initializer_text(self, pool: memhub.MemBuddy*, var_ty: mlirlite.LLVMType*, str_val: str) -> str: """Build initializer text for an array global from a string literal; None on failure.""" if var_ty is None or str_val is None: return None @@ -461,11 +464,11 @@ novirtual class TranslatorGenMixin: return 0 # handle_module_level_var - module-level var declaration -> LLVM global (int/list/string init). - # _RegisterStaticModuleVar - register (name, def module SHA1) of t.CStatic vars for cross-module access checks. + # _RegisterStaticModuleVar - register (name, def module SHA1) of t.StaticT vars for cross-module access checks. def _RegisterStaticModuleVar(self, trans: HT.Translator*, annot_node: ast.AST*, var_name: str) -> int: if trans is None or annot_node is None or var_name is None: return 0 if trans.ModuleSha1 is None: return 0 - if self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CStatic", 0) == 0: return 0 + if self.Gen.TypeGenErr.has_decorator_marker(annot_node, "StaticT", 0) == 0: return 0 self.Gen.CallGenBase.RegisterStaticSymbol(trans.ModuleSha1, var_name) return 0 @@ -475,8 +478,8 @@ novirtual class TranslatorGenMixin: pool: memhub.MemBuddy* = trans.Pool mod: mlirlite.LLVMModule* = trans.Module - # CDefine annotation: a compile-time constant, no global is created; register it in the - # global CDefine table so t.CArray[elem_ty, NAME] can resolve it. + # DefineT annotation: a compile-time constant, no global is created; register it in the + # global DefineT table so t.ArrayT[elem_ty, NAME] can resolve it. k: int = node.kind() if k == ast.ASTKind.AnnAssign: aa_cd: ast.AnnAssign* = ast.AnnAssign*(node) @@ -485,18 +488,18 @@ novirtual class TranslatorGenMixin: nm_cd: ast.Name* = ast.Name*(aa_cd.target) if nm_cd.id is not None: if self.Gen.AssignGen.is_cdefine_annotation(aa_cd.annotation) != 0: - # Auto-detect and register float/int CDefine values (e.g. vipermath U_M_PI) + # Auto-detect and register float/int DefineT values (e.g. vipermath U_M_PI) self.Gen.AssignGen._register_cdefine_from_value(pool, nm_cd.id, aa_cd.value, aa_cd.annotation) return 0 - # CTypedef annotation: no global is created (would duplicate the symbol); - # register it in the CTypedef table instead, or annotation lookups fail. + # TypedefT annotation: no global is created (would duplicate the symbol); + # register it in the TypedefT table instead, or annotation lookups fail. if self.Gen.TypeGenCType._is_ctypedef_annotation(aa_cd.annotation) != 0: ctd_str: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, aa_cd.value) if ctd_str is not None: self.Gen.TypeGenCType.register_ctypedef(pool, nm_cd.id, ctd_str) return 0 - # In _declare_only=1 (struct-registration) mode only CDefine is handled; reaching here - # means it is not a CDefine, so skip. + # In _declare_only=1 (struct-registration) mode only DefineT is handled; reaching here + # means it is not a DefineT, so skip. if trans._declare_only == 1: return 0 var_name: str = None @@ -512,7 +515,7 @@ novirtual class TranslatorGenMixin: # Explicit `= None` init keeps lazy-initialization pointer semantics: the global must stay # NULL, so no BSS storage is created (storage would break the `!= None` guard). is_none_init: int = 0 - annot_node: ast.AST* = None # Annotation node (used to detect t.CExport markers) + annot_node: ast.AST* = None # Annotation node (used to detect t.ExportT markers) if k == ast.ASTKind.AnnAssign: aa: ast.AnnAssign* = ast.AnnAssign*(node) @@ -524,7 +527,7 @@ novirtual class TranslatorGenMixin: # f-string escape: a module-level initial value is global, but the f-string result # points into the current function's stack buffer -> fail-fast (use escape_fstring_copy). GenApi.fail_if_fstring_escape(aa.value, "global variable initialization") - # t.CStatic vars (no cross-module use) are registered as (name, def module SHA1); + # t.StaticT vars (no cross-module use) are registered as (name, def module SHA1); # the logic stays inside _RegisterStaticModuleVar to avoid disturbing type inference. self._RegisterStaticModuleVar(trans, annot_node, var_name) # Module-level t.Callable function pointers register (name -> return type) here so @@ -541,18 +544,10 @@ novirtual class TranslatorGenMixin: self.Gen.TypeGenResolve.reject_ref_marker_position(aa.annotation, trans._imported_modules, "a module-level variable declaration") resolved: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0) if resolved is not None: - # Object-class module vars (@t.Object/@t.CVTable: object-as-pointer) wrap the - # resolved struct value in Ptr; pure t.CStruct keeps a value instance. + # Object-class module vars (@t.Object/@t.VTableT: object-as-pointer) wrap the + # resolved struct value in Ptr; pure t.StructBase keeps a value instance. if resolved.kind() == mlirlite.LLVMType.Struct: gv_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(resolved) - # [TEMP-DIAG] 模块级 struct 全局的类型决策(定位完删除): - # hasnew/hasvtable/isoop 任一为真 ⇒ 全局被包成 Ptr(指针槽), - # 与"局部变量=值本体"不一致 ⇒ `CAM = V3(...)` 被当成把栈地址交给全局。 - gv_hn: int = -1; gv_hv: int = -1; gv_oo: int = -1 - if gv_entry is not None: - gv_hn = gv_entry.HasNew; gv_hv = gv_entry.HasVTable; gv_oo = gv_entry.IsOOP - stdio.printf("[GVAR-DIAG] name=%s hasnew=%d hasvtable=%d isoop=%d\n", - var_name, gv_hn, gv_hv, gv_oo) if gv_entry is not None and gv_entry.HasNew != 0: # 只有定义了 `__new__`(自定义分配器,对象存储可能不在本帧)的类才**必须** # 以指针表示。仅"有方法 / 带 vtable"(IsOOP / HasVTable)的类,值本体内联 @@ -609,7 +604,7 @@ novirtual class TranslatorGenMixin: else: # 负浮点字面量 `-100.0` = UnaryOp(USub, Constant(float)):按**浮点初始化** # 处理(init_kind=4,值稍后从源码重读,故负号会被保留); - # 否则会被送进整型常量提取器 ⇒ TypeError: CDefine value extraction failed。 + # 否则会被送进整型常量提取器 ⇒ TypeError: DefineT value extraction failed。 is_neg_f: int = 0 if uop_g.op == ast.OpKind.USub and uop_g.operand is not None and uop_g.operand.kind() == ast.ASTKind.Constant: opf_d: ast.Constant* = ast.Constant*(uop_g.operand) @@ -705,14 +700,14 @@ novirtual class TranslatorGenMixin: # struct type in var_ty, or llc reports "use of undefined type named 'sha1.ClassName'". mlirlite.module_ensure_opaque_for_type(mod, pool, var_ty) # Module-level globals are SHA1-prefixed (like function mangling) to avoid duplicate - # symbols; SymTab keys stay bare, and t.CExport globals keep bare names for asm references. + # symbols; SymTab keys stay bare, and t.ExportT globals keep bare names for asm references. is_global_cexport: int = 0 - if annot_node is not None: is_global_cexport = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CExport", 0) - # extern globals (annotation has t.State/t.CExtern) are declared only: `@bare = external + if annot_node is not None: is_global_cexport = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "ExportT", 0) + # extern globals (annotation has t.State/t.ExternT) are declared only: `@bare = external # global T` with external linkage, no initializer and no storage; export instead defines them. is_global_extern: int = 0 if annot_node is not None: - is_global_extern = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CExtern", 0) + is_global_extern = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "ExternT", 0) if is_global_extern == 0: is_global_extern = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "State", 0) # Global-side t.attr.* attributes (`T | t.attr.xxx` union): section->gv.Section, # aligned->gv.Align, weak->gv.Linkage; only present for AnnAssign (annot_node not None). @@ -776,7 +771,7 @@ novirtual class TranslatorGenMixin: # Initializer build failed: error out (fail-fast) instead of falling back self.Gen.TypeGenErr.fatal_error(node, f"failed to build the initializer of module-level variable '{var_name}'", "TypeError") elif init_kind == 3: - # String literal initializer: for array types (t.CArray[char, N]) use a byte-array + # String literal initializer: for array types (t.ArrayT[char, N]) use a byte-array # initializer (content + zero padding); a string-pointer GEP initializer would mismatch. is_arr_g: int = 0 match var_ty: @@ -789,7 +784,7 @@ novirtual class TranslatorGenMixin: if arr_str_init is not None: gv.Initializer = arr_str_init else: self.Gen.TypeGenErr.fatal_error(node, f"failed to build the string initializer of module-level array variable '{var_name}'", "TypeError") else: - # Pointer type (e.g. b64_tab: t.CArray[char, None] = "ABC..."): create an internal + # Pointer type (e.g. b64_tab: t.ArrayT[char, None] = "ABC..."): create an internal # string constant global and reference it via a GEP initializer. str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val) if str_init is not None: gv.Initializer = str_init @@ -842,7 +837,7 @@ novirtual class TranslatorGenMixin: # Value-type storage needs a full struct definition, since cross-module classes are # opaque by default and a zeroinitializer global would report "use of undefined type". self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, resolved_stg_ty) - # @t.CVTable object classes initialize storage field 0 (vtable pointer) to the vtable + # @t.VTableT object classes initialize storage field 0 (vtable pointer) to the vtable # address; otherwise the entry virtual call jumps to 0x0. @t.Object stays zeroinitializer. stg_init_text: str = "zeroinitializer" if resolved_stg_entry is not None and resolved_stg_entry.Name is not None and resolved_stg_entry.HasVTable != 0: @@ -939,14 +934,14 @@ novirtual class TranslatorGenMixin: # Register in the module scope if self.Gen.VarGen.define_module_var(trans.SymTab, var_name, gv_ref) == 0: - # t.CVolatile storage marker (union annotation): mark the global volatile so all + # t.VolatileT storage marker (union annotation): mark the global volatile so all # loads/stores carry LLVM volatile and busy-wait loops are not optimized away. if annot_node is not None: - # const object global: a non-pointer annotation with t.CConst registers IsConst, + # const object global: a non-pointer annotation with t.ConstT registers IsConst, # making later assignment/aug-assign/element-assign to the name fail-fast. if self.Gen.TypeGenErr.is_const_object_marker(annot_node, var_ty) != 0: self.Gen.VarGen.set_var_const(trans.SymTab, var_name) - if self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CVolatile", 0) != 0: self.Gen.VarGen.set_var_volatile(trans.SymTab, var_name) - # rawptr[t.CVolatile | T] (volatile pointee): loads/stores through p[i]/p.field/ + if self.Gen.TypeGenErr.has_decorator_marker(annot_node, "VolatileT", 0) != 0: self.Gen.VarGen.set_var_volatile(trans.SymTab, var_name) + # rawptr[t.VolatileT | T] (volatile pointee): loads/stores through p[i]/p.field/ # c.Deref(p) carry volatile; distinct from the variable's own volatile qualifier. if self.Gen.TypeGenErr.has_pointee_volatile_marker(annot_node) != 0: self.Gen.VarGen.set_var_pointee_volatile(trans.SymTab, var_name) # Set AnnotClassName so attribute access can fall back to the class name when a union diff --git a/App/lib/core/builtin/ViperBuild.vp b/App/lib/core/builtin/ViperBuild.vp index 829f855..3703cdc 100644 --- a/App/lib/core/builtin/ViperBuild.vp +++ b/App/lib/core/builtin/ViperBuild.vp @@ -1065,6 +1065,12 @@ def _HandleCDLL(node: ast.AST*, handle: str) -> int: return rc_s +# IsCdlLDeclCall - 供 Gen 层判断"这条模块级赋值是 ffilib.CDLL 声明"(纯编译期配置,不能生成全局) +def IsCdlLDeclCall(node: ast.AST*) -> int: + """node 是 ffilib.CDLL(...) 调用时返回 1""" + return _IsCDLLCall(node) + + # FfiHandlePath - 查询 extern name(...) 的库路径(runtime=True 的 thunk 用它 LoadLibraryA) def FfiHandlePath(name: str) -> str: """库路径;未登记返回 None"""