1) _ctor_call_agg_ty 增加 REnum 变体构造识别:`EnumType.Variant(...)` 的变体名不是结构体名 (find_struct 必 miss)⇒ 取属性链最右裸名,若判为基础枚举则返回该枚举的聚合类型。 否则 `*槽 = <boxed 变体>` 会被「指针 → 非基本类型值」禁令拦下—— 现场 ClassGenDef.vp:128 `*existing.Ty = llvmlite.LLVMType.Struct(...)`。 2) 按用户要求简化 Error 输出:CastError 只报问题(原因 + 源/目标类型),去掉 ";出错表达式: <形态>(行/列)源码: ..." 后缀(文件与行号已由 TypeGenErr 的 Traceback 帧给出,属重复展示),并删除随之失去调用点的 _cast_fail_where / _source_snippet。
465 lines
22 KiB
Plaintext
465 lines
22 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import lib.core.Gen.Translator as HT
|
||
|
||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||
|
||
# ============================================================
|
||
# f-string 翻译常量(与 ExprGenMixin 保持一致,本地副本避免跨模块
|
||
# CDefine 查找 bug:ExprGenFstr(F) 在 ExprGenMixin(M) 之前按文件序
|
||
# 编译时,跨模块 CDefine 全局表未注册 → NameError 未定义)
|
||
# ============================================================
|
||
define FSTR_BUF_SIZE = 1024
|
||
define FSTR_SPEC_MAX = 64
|
||
define FSTR_FMT_MAX = 64
|
||
|
||
# ============================================================
|
||
# ExprGenFstr - ExprGenMixin 拆分(阶段 D):f-string/格式化值翻译
|
||
# ============================================================
|
||
novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||
"""f-string/格式化值翻译"""
|
||
|
||
# ============================================================
|
||
# translate_joined_str - f-string 翻译(对齐 TPC _HandleJoinedStrLlvm)
|
||
#
|
||
# f"..."(JoinedStr)→ 拼接字面量与格式说明符 → snprintf 生成 i8*
|
||
# 栈缓冲(每站点独立,线程安全);结果是**函数内临时值,禁止逃逸**
|
||
# (return / 存字段 / 存全局 由 GenApi.fail_if_fstring_escape 拦;
|
||
# 需逃逸用 GenApi.escape_fstring_copy 显式拷贝)。
|
||
# 之前 f-string 未翻译导致 print/赋值拿到 NULL 指针
|
||
# ("(null)"输出 + printf("%s", 垃圾) 崩溃 0xC0000005)。
|
||
# ============================================================
|
||
def translate_joined_str(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
node: ast.AST*,
|
||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||
"""f-string → snprintf 生成 i8* 栈缓冲(函数内临时值,禁止逃逸)"""
|
||
if node is None or builder is None or trans is None: return None
|
||
js: rawptr[ast.JoinedStr] = rawptr[ast.JoinedStr](node)
|
||
if js is None or js.values is None: return None
|
||
|
||
# 编译期格式串缓冲(pool 分配)
|
||
fmt_buf: str = pool.alloc(FSTR_BUF_SIZE)
|
||
if fmt_buf is None: return None
|
||
fmt_buf[0] = '\0'
|
||
|
||
# 运行时参数链表(Value.Next 链接,与 printf 调用一致)
|
||
arg_head: llvmlite.Value* = None
|
||
arg_tail: llvmlite.Value* = None
|
||
arg_count: int = 0
|
||
|
||
parts: list[ast.AST*]* = js.values
|
||
pn: sizet = len(parts)
|
||
for pi in range(pn):
|
||
part: ast.AST* = parts.get(pi)
|
||
if part is None: continue
|
||
if part.kind() == ast.ASTKind.Constant:
|
||
pcn: ast.Constant* = ast.Constant*(part)
|
||
if pcn.const_kind == ast.CONST_STR and pcn.str_val is not None:
|
||
self._fstr_append_literal(fmt_buf, pcn.str_val)
|
||
continue
|
||
if part.kind() != ast.ASTKind.FormattedValue: continue
|
||
fv: rawptr[ast.FormattedValue] = rawptr[ast.FormattedValue](part)
|
||
if fv.value is None: continue
|
||
val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fv.value, None, 0, trans)
|
||
if val is None:
|
||
# fail-fast:f-string 格式化值翻译失败必须终止编译,绝不在
|
||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||
continue
|
||
# 确定 C 格式说明符(format_spec 优先,否则按值类型推断)
|
||
c_fmt: str = None
|
||
if fv.format_spec is not None:
|
||
c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value)
|
||
if c_fmt is None:
|
||
c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
|
||
if c_fmt is None:
|
||
# fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译
|
||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError")
|
||
# 追加格式说明符
|
||
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1:
|
||
string.strcat(fmt_buf, c_fmt)
|
||
# 转换参数类型(i8/i16→i32、bool→i32、f32→f64)
|
||
cast_val: llvmlite.Value* = self._fstr_cast_value(builder, pool, val, c_fmt, fv.value, trans)
|
||
if cast_val is None:
|
||
cast_val = val
|
||
cast_val.Next = None
|
||
if arg_head is None:
|
||
arg_head = cast_val
|
||
else:
|
||
arg_tail.Next = cast_val
|
||
arg_tail = cast_val
|
||
arg_count += 1
|
||
|
||
return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans)
|
||
def translate_formatted_value(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
node: ast.AST*,
|
||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||
"""翻译裸 FormattedValue(f"{expr:spec}" 无字面量时解析器返回 FormattedValue 而非 JoinedStr)"""
|
||
if node is None or builder is None or trans is None:
|
||
return None
|
||
fv: rawptr[ast.FormattedValue] = rawptr[ast.FormattedValue](node)
|
||
if fv is None or fv.value is None:
|
||
return None
|
||
fmt_buf: str = pool.alloc(FSTR_BUF_SIZE)
|
||
if fmt_buf is None:
|
||
return None
|
||
fmt_buf[0] = '\0'
|
||
arg_head: llvmlite.Value* = None
|
||
arg_tail: llvmlite.Value* = None
|
||
arg_count: int = 0
|
||
val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fv.value, None, 0, trans)
|
||
if val is None:
|
||
# fail-fast:裸 FormattedValue 翻译失败必须终止编译,绝不在
|
||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||
else:
|
||
c_fmt: str = None
|
||
if fv.format_spec is not None:
|
||
c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value)
|
||
if c_fmt is None:
|
||
c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
|
||
if c_fmt is None:
|
||
# fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译
|
||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError")
|
||
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1:
|
||
string.strcat(fmt_buf, c_fmt)
|
||
cast_val: llvmlite.Value* = self._fstr_cast_value(builder, pool, val, c_fmt, fv.value, trans)
|
||
if cast_val is None:
|
||
cast_val = val
|
||
cast_val.Next = None
|
||
arg_head = cast_val
|
||
arg_tail = cast_val
|
||
arg_count = 1
|
||
return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans)
|
||
def _fstr_finalize(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
fmt_buf: str,
|
||
arg_head: llvmlite.Value*,
|
||
arg_tail: llvmlite.Value*,
|
||
arg_count: int,
|
||
trans: HT.Translator*) -> llvmlite.Value*:
|
||
"""f-string 尾部:全局格式串 + 每站点栈缓冲 + snprintf,返回 i8*(函数内临时值)"""
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
if fmt_buf is None or fmt_buf[0] == '\0':
|
||
# 空 f-string(f"")→ 空字符串常量
|
||
return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, "", trans)
|
||
# 格式串 → 全局字符串常量(i8*)
|
||
fmt_ptr: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fmt_buf, trans)
|
||
if fmt_ptr is None: return None
|
||
# 结果缓冲:**每站点独立栈缓冲**(entry 块 alloca;每次翻译本站点各建一个,
|
||
# 站点之间不共享 ⇒ 同函数多个 f-string 不再互相覆盖)。
|
||
#
|
||
# 语义(用户 2026-09-27 决定):f-string 结果是**当前函数内的临时值**。
|
||
# · 栈缓冲 ⇒ 线程安全(每个线程各自一份栈帧,同站点并发也不串味)
|
||
# + 零运行时依赖(内核没有 C-ABI malloc,也不能假设任何分配器);
|
||
# · 函数返回即失效 ⇒ **禁止逃逸**:return / 存字段 / 存全局 / 存容器一律
|
||
# 由 GenApi.fail_if_fstring_escape 在翻译期 fail-fast 拦下。历史事故:
|
||
# 旧实现让调用方把该栈指针 return 出去,再作 %s 喂 snprintf ⇒
|
||
# ASan stack-buffer-underflow in vsnprintf(READ size 1,栈左红区)。
|
||
# · 确需逃逸时**显式分配后拷贝**:GenApi.escape_fstring_copy
|
||
# (stdlib.malloc + string.strcpy);编译器自身的报文构造即此写法
|
||
# (AssignGenMixin.const_assign_msg)。
|
||
buf_ty: llvmlite.LLVMType* = llvmlite.Array(pool, i8_ty, FSTR_BUF_SIZE)
|
||
buf_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, buf_ty)
|
||
if buf_alloca is None: return None
|
||
zero_i32: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||
buf_ptr: llvmlite.Value* = llvmlite.build_gep_array(builder, buf_ty, i8_ty, buf_alloca, zero_i32)
|
||
if buf_ptr is None: return None
|
||
# snprintf(buf, FSTR_BUF_SIZE, fmt, args...)
|
||
size_val: llvmlite.Value* = llvmlite.const_int64(pool, FSTR_BUF_SIZE)
|
||
buf_ptr.Next = size_val
|
||
size_val.Next = fmt_ptr
|
||
fmt_ptr.Next = arg_head
|
||
if arg_tail is not None:
|
||
arg_tail.Next = None
|
||
llvmlite.build_call(builder, "snprintf", buf_ptr, 3 + arg_count, i32_ty, 1)
|
||
return buf_ptr
|
||
def _fstr_append_literal(self, fmt_buf: str,
|
||
lit: str) -> None:
|
||
"""追加字面量到格式串(% 转义为 %%)"""
|
||
if fmt_buf is None or lit is None: return
|
||
cur_len: sizet = string.strlen(fmt_buf)
|
||
rem: sizet = FSTR_BUF_SIZE - 1 - cur_len
|
||
if rem == 0: return
|
||
src_len: sizet = string.strlen(lit)
|
||
si: sizet = 0
|
||
while si < src_len and rem > 0:
|
||
ch: char = lit[si]
|
||
if ch == '%':
|
||
if rem < 2:
|
||
break
|
||
fmt_buf[cur_len] = '%'
|
||
fmt_buf[cur_len + 1] = '%'
|
||
cur_len += 2
|
||
rem -= 2
|
||
else:
|
||
fmt_buf[cur_len] = ch
|
||
cur_len += 1
|
||
rem -= 1
|
||
si += 1
|
||
fmt_buf[cur_len] = '\0'
|
||
def _fstr_append_raw(self, fmt_buf: str, s: str) -> None:
|
||
"""追加原始字符串(不做 % 转义)"""
|
||
if fmt_buf is None or s is None:
|
||
return
|
||
cur_len: sizet = string.strlen(fmt_buf)
|
||
src_len: sizet = string.strlen(s)
|
||
if cur_len + src_len < FSTR_BUF_SIZE:
|
||
string.strcpy(fmt_buf + cur_len, s)
|
||
def _fstr_parse_format_spec(self, pool: memhub.MemBuddy*,
|
||
spec_node: ast.AST*,
|
||
val: llvmlite.Value*,
|
||
arg_node: ast.AST*) -> str:
|
||
"""Python format_spec → C printf 格式串(pool 分配),无法解析返回 None"""
|
||
if spec_node is None or pool is None or val is None:
|
||
return None
|
||
# 1. 提取 spec 字符串(JoinedStr 仅常量拼接)
|
||
spec: str = pool.alloc(FSTR_SPEC_MAX)
|
||
if spec is None:
|
||
return None
|
||
spec[0] = '\0'
|
||
sk: int = spec_node.kind()
|
||
if sk == ast.ASTKind.JoinedStr:
|
||
jss: rawptr[ast.JoinedStr] = rawptr[ast.JoinedStr](spec_node)
|
||
if jss.values is None: return None
|
||
vn: sizet = len(jss.values)
|
||
for vi in range(vn):
|
||
vpart: ast.AST* = jss.values.get(vi)
|
||
if vpart is None: continue
|
||
if vpart.kind() != ast.ASTKind.Constant: return None
|
||
vcn: ast.Constant* = ast.Constant*(vpart)
|
||
if vcn.const_kind != ast.CONST_STR or vcn.str_val is None: return None
|
||
if string.strlen(spec) + string.strlen(vcn.str_val) < FSTR_SPEC_MAX - 1:
|
||
string.strcat(spec, vcn.str_val)
|
||
elif sk == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(spec_node)
|
||
if cn.const_kind != ast.CONST_STR or cn.str_val is None:
|
||
return None
|
||
string.strncpy(spec, cn.str_val, FSTR_SPEC_MAX - 1)
|
||
else: return None
|
||
slen: sizet = string.strlen(spec)
|
||
if slen == 0: return None
|
||
|
||
# 2. 逐段解析: [fill]align / sign / # / 0 / width / , / .precision / type
|
||
pos: sizet = 0
|
||
align_char: char = 0
|
||
if pos < slen:
|
||
ch0: char = spec[pos]
|
||
if ch0 == '<' or ch0 == '>' or ch0 == '^' or ch0 == '=':
|
||
align_char = ch0
|
||
pos += 1
|
||
elif pos + 1 < slen:
|
||
ch1: char = spec[pos + 1]
|
||
if ch1 == '<' or ch1 == '>' or ch1 == '^' or ch1 == '=':
|
||
align_char = ch1
|
||
pos += 2
|
||
c_flags: str = pool.alloc(FSTR_FMT_MAX)
|
||
c_width: str = pool.alloc(32)
|
||
c_prec: str = pool.alloc(32)
|
||
if c_flags is None or c_width is None or c_prec is None: return None
|
||
c_flags[0] = '\0'
|
||
c_width[0] = '\0'
|
||
c_prec[0] = '\0'
|
||
# sign
|
||
if pos < slen and (spec[pos] == '+' or spec[pos] == '-' or spec[pos] == ' '):
|
||
if spec[pos] == '+':
|
||
string.strcat(c_flags, "+")
|
||
elif spec[pos] == ' ':
|
||
string.strcat(c_flags, " ")
|
||
pos += 1
|
||
# alt '#'
|
||
if pos < slen and spec[pos] == '#':
|
||
string.strcat(c_flags, "#")
|
||
pos += 1
|
||
# zero '0'
|
||
if pos < slen and spec[pos] == '0':
|
||
string.strcat(c_flags, "0")
|
||
pos += 1
|
||
# 左对齐 '<'/'^' → '-'(与 0 同时存在时 C 语义 '-' 优先)
|
||
if align_char == '<' or align_char == '^':
|
||
string.strcat(c_flags, "-")
|
||
# width digits
|
||
while pos < slen and spec[pos] >= '0' and spec[pos] <= '9':
|
||
wl: sizet = string.strlen(c_width)
|
||
if wl < 30:
|
||
c_width[wl] = spec[pos]
|
||
c_width[wl + 1] = '\0'
|
||
pos += 1
|
||
# comma ',' → C printf 不支持千分位,忽略
|
||
if pos < slen and spec[pos] == ',':
|
||
pos += 1
|
||
# .precision
|
||
if pos < slen and spec[pos] == '.':
|
||
string.strcat(c_prec, ".")
|
||
pos += 1
|
||
while pos < slen and spec[pos] >= '0' and spec[pos] <= '9':
|
||
pl: sizet = string.strlen(c_prec)
|
||
if pl < 30:
|
||
c_prec[pl] = spec[pos]
|
||
c_prec[pl + 1] = '\0'
|
||
pos += 1
|
||
if string.strlen(c_prec) == 1:
|
||
return None # 只有 '.' 无效
|
||
# type char
|
||
fmt_type: char = 0
|
||
if pos < slen:
|
||
fmt_type = spec[pos]
|
||
pos += 1
|
||
if pos != slen: return None # 多余字符无法解析
|
||
|
||
# 3. 长度修饰(按值类型位宽)
|
||
len_mod: str = pool.alloc(4)
|
||
if len_mod is None: return None
|
||
len_mod[0] = '\0'
|
||
ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
||
# 32 位**不写**长度修饰符(N14):`{x:08X}` 的实参是 i32,此前推导出
|
||
# `l` → 格式串 `%08lX`(long)与实参宽度不符(LP64 下 printf 按 64 位
|
||
# 读参 → 变参错位)。与同文件无 spec 路径 `_fstr_infer_c_fmt`(32 位用
|
||
# `%u/%d`)以及 TPC 侧 HandlesExprFormat.py 保持一致。
|
||
if ibits == 64: string.strcpy(len_mod, "ll")
|
||
elif ibits == 16: string.strcpy(len_mod, "h")
|
||
elif ibits == 8: string.strcpy(len_mod, "hh")
|
||
|
||
# 4. 组装 C 格式串
|
||
out: str = pool.alloc(FSTR_FMT_MAX)
|
||
if out is None: return None
|
||
out[0] = '\0'
|
||
string.strcat(out, "%")
|
||
string.strcat(out, c_flags)
|
||
string.strcat(out, c_width)
|
||
string.strcat(out, c_prec)
|
||
if fmt_type == 0:
|
||
# 无 type:按值类型推断
|
||
fbits2: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty)
|
||
if ibits != 0:
|
||
if ibits == 8:
|
||
string.strcat(out, "c")
|
||
elif ibits == 1:
|
||
string.strcat(out, "d")
|
||
else:
|
||
string.strcat(out, len_mod)
|
||
string.strcat(out, "d")
|
||
elif fbits2 != 0:
|
||
string.strcat(out, "f")
|
||
elif self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0:
|
||
string.strcat(out, "s")
|
||
else:
|
||
string.strcat(out, "d")
|
||
elif fmt_type == 'c':
|
||
string.strcat(out, "c")
|
||
elif fmt_type == 'f' or fmt_type == 'F':
|
||
string.strcat(out, "f")
|
||
elif fmt_type == 'e' or fmt_type == 'E' or fmt_type == 'g' or fmt_type == 'G':
|
||
tmp_ch: str = pool.alloc(2)
|
||
if tmp_ch is None:
|
||
return None
|
||
tmp_ch[0] = fmt_type
|
||
tmp_ch[1] = '\0'
|
||
string.strcat(out, tmp_ch)
|
||
elif fmt_type == 's':
|
||
string.strcat(out, "s")
|
||
elif fmt_type == '%':
|
||
string.strcat(out, "%")
|
||
elif fmt_type == 'b':
|
||
return None # 二进制不支持
|
||
elif fmt_type == 'd' or fmt_type == 'i':
|
||
string.strcat(out, len_mod)
|
||
string.strcat(out, "d")
|
||
elif fmt_type == 'x' or fmt_type == 'X' or fmt_type == 'o' or fmt_type == 'u':
|
||
string.strcat(out, len_mod)
|
||
tmp_ch2: str = pool.alloc(2)
|
||
if tmp_ch2 is None:
|
||
return None
|
||
tmp_ch2[0] = fmt_type
|
||
tmp_ch2[1] = '\0'
|
||
string.strcat(out, tmp_ch2)
|
||
else:
|
||
return None
|
||
return out
|
||
def _fstr_infer_c_fmt(self, pool: memhub.MemBuddy*,
|
||
val: llvmlite.Value*,
|
||
arg_node: ast.AST*,
|
||
trans: HT.Translator*) -> str:
|
||
"""无 format_spec 时按值类型推断 C printf 格式(对齐 TPC 无 spec 分支,带 % 前缀)"""
|
||
if val is None or pool is None: return None
|
||
out: str = pool.alloc(16)
|
||
if out is None: return None
|
||
out[0] = '\0'
|
||
ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
||
fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty)
|
||
if ibits == 1: return "%d" # bool
|
||
if ibits == 8: return "%c" # 字符
|
||
if ibits != 0:
|
||
if self.Gen.ExprGenOps._node_type_unsigned(pool, arg_node, trans) != 0:
|
||
if ibits == 64:
|
||
string.strcpy(out, "%llu")
|
||
else:
|
||
string.strcpy(out, "%u")
|
||
else:
|
||
if ibits == 64:
|
||
string.strcpy(out, "%lld")
|
||
else:
|
||
string.strcpy(out, "%d")
|
||
return out
|
||
if fbits != 0:
|
||
return "%f"
|
||
if self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0:
|
||
return "%s"
|
||
# fail-fast:值类型缺失(非整数/浮点/指针),无法推断 C 格式,立即终止编译
|
||
self.Gen.TypeGenErr.fatal_error(arg_node, "f-string 格式无法推断(值类型缺失)", "TypeError")
|
||
return None
|
||
def _fstr_cast_value(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
val: llvmlite.Value*,
|
||
c_fmt: str,
|
||
arg_node: ast.AST*,
|
||
trans: HT.Translator*) -> llvmlite.Value*:
|
||
"""按 C 格式转换值类型(i8/i16→i32、bool→i32、f32→f64)"""
|
||
if val is None or c_fmt is None:
|
||
return None
|
||
# 找格式类型字符(最后一个字母,忽略 l/h 长度修饰)
|
||
fmt_char: char = 0
|
||
flen: sizet = string.strlen(c_fmt)
|
||
fi: sizet = flen
|
||
while fi > 0:
|
||
fi -= 1
|
||
ch: char = c_fmt[fi]
|
||
if ch == '%':
|
||
break
|
||
if (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z'):
|
||
if ch != 'l' and ch != 'h':
|
||
fmt_char = ch
|
||
break
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
if fmt_char == 's':
|
||
return val
|
||
if fmt_char == 'c':
|
||
ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
||
if ibits != 0 and ibits < 32:
|
||
return llvmlite.build_zext(builder, val, i32_ty)
|
||
return val
|
||
if fmt_char == 'd' or fmt_char == 'i' or fmt_char == 'x' \
|
||
or fmt_char == 'X' or fmt_char == 'o' or fmt_char == 'u':
|
||
ibits = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
||
if ibits == 1:
|
||
return llvmlite.build_zext(builder, val, i32_ty)
|
||
if ibits == 8 or ibits == 16:
|
||
if self.Gen.ExprGenOps._node_type_unsigned(pool, arg_node, trans) != 0:
|
||
return llvmlite.build_zext(builder, val, i32_ty)
|
||
return llvmlite.build_sext(builder, val, i32_ty)
|
||
return val
|
||
if fmt_char == 'f' or fmt_char == 'e' or fmt_char == 'E' \
|
||
or fmt_char == 'g' or fmt_char == 'G':
|
||
fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty)
|
||
if fbits == 32:
|
||
return llvmlite.build_fpext(builder, val, llvmlite.Double(pool))
|
||
return val
|
||
return val |