diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index 92154f9..2269fa6 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -478,6 +478,30 @@ novirtual class TranslatorGenMixin: return 0 + # _module_init_from_cdefine - resolve a module-level initializer that is a bare DefineT name. + # Without this the initializer is silently dropped and the global becomes zero/BSS + # (e.g. `_text_mode: int = TEXT_MODE_MANAGED` ran as 0). + def _module_init_from_cdefine(self, name: str, kind_out: int*, val_out: int64*, fval_out: double*, sval_out: str*) -> int: + """Fill the initializer kind/value from a DefineT name; 1 when resolved, 0 otherwise.""" + if name is None: return 0 + cv: int64 = self.Gen.TypeGenCDef.lookup_cdefine_constant(name) + if self.Gen.TypeGenCDef.is_cdefine_found() == 0: return 0 + if self.Gen.TypeGenCDef.is_cdefine_str() != 0: + sv: str = self.Gen.TypeGenCDef.lookup_cdefine_string(name) + if sv is None: return 0 + if sval_out is not None: sval_out[0] = sv + if kind_out is not None: kind_out[0] = 3 + return 1 + if self.Gen.TypeGenCDef.is_cdefine_double() != 0: + dv: double = self.Gen.TypeGenCDef.lookup_cdefine_double(name) + if fval_out is not None: fval_out[0] = dv + # Kind 6: float value already known, so emission must not re-read a source literal. + if kind_out is not None: kind_out[0] = 6 + return 1 + if val_out is not None: val_out[0] = cv + if kind_out is not None: kind_out[0] = 1 + return 1 + def handle_module_level_var(self, trans: HT.Translator*, node: ast.AST*) -> int: """Handle a module-level variable declaration by creating its global.""" pool: memhub.MemBuddy* = trans.Pool @@ -627,6 +651,12 @@ novirtual class TranslatorGenMixin: elif val_kind == ast.ASTKind.List: init_list_node = ast.List*(aa.value) init_kind = 2 + elif val_kind == ast.ASTKind.Name: + # DefineT reference (`g: int = SOME_DEFINE`): resolve at compile time, else the + # global is created without an initializer and silently becomes 0/BSS. + nv_g: ast.Name* = ast.Name*(aa.value) + if nv_g is not None and nv_g.id is not None: + self._module_init_from_cdefine(nv_g.id, &init_kind, &init_val, &init_fval, &init_str_val) elif k == ast.ASTKind.Assign: asgn: ast.Assign* = ast.Assign*(node) if asgn is None or asgn.targets is None: return 0 @@ -675,6 +705,14 @@ novirtual class TranslatorGenMixin: elif val_kind2 == ast.ASTKind.List: init_list_node = ast.List*(asgn.value) init_kind = 2 + elif val_kind2 == ast.ASTKind.Name: + # DefineT reference without an annotation; the define's kind decides the + # inferred type (int -> i32, float -> double, string -> str pointer). + nv_g2: ast.Name* = ast.Name*(asgn.value) + if nv_g2 is not None and nv_g2.id is not None: + self._module_init_from_cdefine(nv_g2.id, &init_kind, &init_val, &init_fval, &init_str_val) + if init_kind == 6: var_ty = mlirlite.Double(pool) + elif init_kind == 3: var_ty = mlirlite.Ptr(pool, mlirlite.Int8(pool)) elif val_kind2 == ast.ASTKind.Attribute: # Module-level re-export alias (e.g. `_read32 = types._read32`): the RHS is an # entity reference with no value semantics, so emit no LLVM global (same as __all__). @@ -688,7 +726,8 @@ novirtual class TranslatorGenMixin: # Float literal init (init_kind==4): re-read the value from source by name instead of the # AST float_val (which pool ops may overwrite); also validate that the annotation is float. - if init_kind == 4: + # init_kind==6 is a float already resolved from a DefineT, so no source re-read applies. + if init_kind == 4 or init_kind == 6: is_fty_g: int = 0 match var_ty: case mlirlite.LLVMType.Float(_): @@ -698,9 +737,10 @@ novirtual class TranslatorGenMixin: if is_fty_g == 0: self.Gen.TypeGenErr.fatal_error(node, f"module-level variable '{var_name}' is initialized with a float literal, but its annotation is not a float type", "TypeError") return 0 - if self.Gen.AssignGen._recover_float_literal(var_name, &init_fval, 0) != 1: - self.Gen.TypeGenErr.fatal_error(node, f"failed to recover the initializer value of module-level float variable '{var_name}' from the source file", "InternalCompilerError") - return 0 + if init_kind == 4: + if self.Gen.AssignGen._recover_float_literal(var_name, &init_fval, 0) != 1: + self.Gen.TypeGenErr.fatal_error(node, f"failed to recover the initializer value of module-level float variable '{var_name}' from the source file", "InternalCompilerError") + return 0 # Check whether it is already registered existing: mlirlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, var_name) @@ -799,7 +839,7 @@ novirtual class TranslatorGenMixin: 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 else: self.Gen.TypeGenErr.fatal_error(node, f"failed to build the initializer of module-level variable '{var_name}'", "TypeError") - elif init_kind == 4: + elif init_kind == 4 or init_kind == 6: # Float initializer: LLVM float constants must be written as bit-pattern text # (0x%016llx / 0x%08x); decimal text has ulp errors, and omitting this zeroes the global. fc_g: mlirlite.Value* = mlirlite.ConstFloat(pool, var_ty, init_fval)