diff --git a/App/lib/core/Gen/Expr/ExprGenOps.vp b/App/lib/core/Gen/Expr/ExprGenOps.vp index 740f48e..d547d42 100644 --- a/App/lib/core/Gen/Expr/ExprGenOps.vp +++ b/App/lib/core/Gen/Expr/ExprGenOps.vp @@ -251,15 +251,13 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): if self._annot_str_unsigned(scn_u) != 0: return 1 return 0 if k == ast.ASTKind.Attribute: - # Struct field (e.g. viperio.Buf's self.capacity/length: sizet): get the class name from the receiver's AnnotClassName, then look up the field annotation to decide unsignedness. Read-only; returns 0 on failure, so find_struct + manual field walk is used instead of lookup_field_by_class. + # Struct field (e.g. viperio.Buf's self.capacity/length: sizet): decide unsignedness from the + # *field's* annotation, resolved through the receiver's struct class name. The receiver is not + # limited to a plain variable name: it may be a nested field (a.b.f), an index/deref + # (arr[i].f / ptr[i].f) or a module-qualified global (pkg.mod.g[i].f). Read-only; 0 = unresolved. at_u: ast.Attribute* = ast.Attribute*(node) if at_u.value is not None and at_u.attr is not None and trans is not None: - cls_nm_u: str = None - if at_u.value.kind() == ast.ASTKind.Name: - vn_u: ast.Name* = ast.Name*(at_u.value) - if vn_u.id is not None: - ve_u: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, vn_u.id) - if ve_u is not None: cls_nm_u = self.Gen.VarGen.var_annot_class_name(ve_u) + cls_nm_u: str = self._attr_receiver_class_name(pool, at_u.value, trans) if cls_nm_u is not None: # Take the bare class name (before the dot): look up by bare name only, avoiding module-qualified resolution bare_u: str = cls_nm_u @@ -279,6 +277,72 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): break return 0 return 0 + # _attr_receiver_class_name - struct class name of an attribute receiver expression. Resolves by the + # receiver's *type*, not by shape: variable/field annotation class name (Name / nested Attribute), the + # same resolution one array/pointer level down for an index/deref base (arr[i] / ptr[i]), or the global's + # element type for a module-qualified global (Mod.g / pkg.mod.g). None when unresolved. + def _attr_receiver_class_name(self, pool: memhub.MemBuddy*, node: ast.AST*, trans: HT.Translator*) -> str: + """Struct class name of an attribute receiver (Name / Attribute / Subscript); None if unresolved.""" + if node is None or trans is None: return None + k: int = node.kind() + if k == ast.ASTKind.Subscript: + # arr[i].f / ptr[i].f: the element sits one array/pointer level below the base, and the base's + # class-name resolution already denotes that element struct (the levels are transparent here), + # so resolve the subscript base directly. + sub_rc: ast.Subscript* = ast.Subscript*(node) + if sub_rc.value is None: return None + return self._attr_receiver_class_name(pool, sub_rc.value, trans) + if k == ast.ASTKind.Attribute: + # Module-qualified global (Mod.g / pkg.mod.g): the class name comes from the global's element type. + gc_rc: str = self._module_global_element_class(pool, trans, ast.Attribute*(node)) + if gc_rc is not None: return gc_rc + # Object field chain (a.b.f): the field's annotation class name (recursive). + return self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, node, 1) + if k == ast.ASTKind.Name: + nm_rc: ast.Name* = ast.Name*(node) + if nm_rc.id is None: return None + ve_rc: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_rc.id) + if ve_rc is None: return None + return self.Gen.VarGen.var_annot_class_name(ve_rc) + return None + # _module_global_element_class - element class name of a module-qualified global `Mod.g`. The module path + # may be multi-component (e.g. `intr.idt.idt`: package intr -> submodule idt -> global idt). Mirrors + # ExprGenAttr._resolve_module_global_class_name but accepts a dotted module path and also unwraps an array + # element, so a module-global array such as `idt: [256]idt_entry` resolves to 'idt_entry'. None otherwise. + def _module_global_element_class(self, pool: memhub.MemBuddy*, trans: HT.Translator*, at: ast.Attribute*) -> str: + """Element class name of the module-qualified global `at.value.at.attr`; None when not a global.""" + if at is None or at.value is None or at.attr is None or trans is None: return None + if trans._imported_modules is None or trans.Module is None: return None + mod_path: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, at.value) + if mod_path is None: return None + # restore import aliases (import X.Y as Z) so the import/SHA1 checks resolve + if trans._from_imports is not None: + orig_mg: str = self.Gen.ImportsGen.lookup_from_import(trans._from_imports, mod_path, 0) + if orig_mg is not None: + oml_mg: sizet = 0 + while orig_mg[oml_mg] != ' ' and orig_mg[oml_mg] != '\0' and orig_mg[oml_mg] != ':': oml_mg += 1 + if oml_mg > 0: + om_buf_mg: str = pool.alloc(oml_mg + 1) + if om_buf_mg is not None: + string.strncpy(om_buf_mg, orig_mg, oml_mg) + om_buf_mg[oml_mg] = '\0' + mod_path = om_buf_mg + # package submodules (`intr.idt`) count as known when the package is imported + if self.Gen.ImportsGen.is_module_imported_or_known(trans._imported_modules, mod_path) == 0: return None + gv: mlirlite.GlobalVariable* = self.Gen.ExprGenAttr.find_global_in_module(trans.Module, self.Gen.FuncGenBase._mangle_name_with_sha1(self.Gen.ExprGenAttr._lookup_module_sha1(mod_path), at.attr)) + if gv is None: gv = self.Gen.ExprGenAttr.find_global_in_module(trans.Module, at.attr) + if gv is None or gv.Ty is None: return None + # a global is usually `Element*` / `Element**` or an array `[N]Element`: descend to the leaf type + # and take its registered struct class name. + elem_ty: mlirlite.LLVMType* = gv.Ty + lvl_mg: int = 0 + while elem_ty is not None and lvl_mg < 4: + match elem_ty: + case mlirlite.LLVMType.Ptr(inner_mg): elem_ty = inner_mg + case mlirlite.LLVMType.Array(elem_mg, _): elem_ty = elem_mg + case _: return self.Gen.StructGen.get_class_name_by_type(pool, elem_ty) + lvl_mg += 1 + return None def _node_type_signed(self, pool: memhub.MemBuddy*, node: ast.AST*, trans: HT.Translator* = None) -> int: """Return 1 if the source node is explicitly a signed integer, else 0.""" if node is None: return 0 @@ -700,6 +764,13 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): case mlirlite.LLVMType.Struct(_, _, _): obj_ty_ao: mlirlite.LLVMType* = mlirlite.Ptr(pool, ao2) return mlirlite.build_load(builder, obj_ty_ao, v_ao) + case mlirlite.LLVMType.Func(_, _, _): + # 函数指针变量(嵌套函数名在符号表里是 Ptr(Func)):变量本身就是 + # 那个函数地址,`&f` 应给出它的值 Ptr(Func)(一级),而不是变量 + # 地址 Ptr(Ptr(Func))(二级)——否则传给 callback: t.CPtr 会因 + # 级数不符报 CastError(source level 2 -> target level 1)。 + fp_ty_ao: mlirlite.LLVMType* = mlirlite.Ptr(pool, ao2) + return mlirlite.build_load(builder, fp_ty_ao, v_ao) case _: pass case _: