Skip to main content

libperl_macrogen/
static_array_emitter.rs

1//! `GlobalConstDict` の静的 const 配列を Rust の `static` 配列定義として
2//! 出力する。
3//!
4//! 典型例: `sv_inline.h` の `bodies_by_type[]` を `Perl_newSV_type` 等で
5//! 参照可能にするため、Rust 側で同じ初期値の `static` を生成する。
6//! 元の C コードでは `static const` (翻訳単位ローカル) なので、別 TU 相当
7//! として独自にデータを持つことに意味論的な問題はない。
8//!
9//! ### 翻訳ルール
10//!
11//! 各 initializer エントリ(無名 compound `{ a, b, c, ... }`)を struct
12//! literal に変換する。位置順なので、対応する `StructDef.members` の名前
13//! を順に取り出して `body_details { body_size: a, copy: b, ... }` の形式に
14//! 整形する。
15//!
16//! Bitfield 連続グループは値を pack して `_bitfield_N: ((v0 as u8) & mask0)
17//! | ((v1 as u8) << shift1) | ...` の形で 1 つのフィールドにまとめる。
18//!
19//! 各値の式翻訳は `translate_const_expr` で行う。マクロは preprocessor
20//! で展開済みのため、`+`, `-`, `*`, `?:`, `cast`, `sizeof`, `__builtin_offsetof`
21//! など純粋な C 式のみを扱えば良い。
22
23use crate::ast::{BuiltinArg, Expr, ExprKind, Initializer};
24use crate::fields_dict::{FieldsDict, StructDef};
25use crate::global_const_dict::{GlobalConstDecl, GlobalConstDict};
26use crate::intern::{InternedStr, StringInterner};
27use crate::rust_decl::RustDeclDict;
28use crate::type_repr::TypeRepr;
29
30/// 出力結果と、正常に emit できた static 配列名の集合。
31/// 名前集合は下流の codegen で `.as_ptr()` 減衰判定 (is_array_like_expr)
32/// などに使う。
33pub struct EmittedStaticArrays {
34    pub source: String,
35    pub emitted_names: std::collections::HashSet<String>,
36    /// 名前 → Rust 型文字列 (`"[ELEMENT; N]"` 形式)。
37    /// `BindingsInfo::static_types` にマージして要素型抽出に使う。
38    pub emitted_types: std::collections::HashMap<String, String>,
39}
40
41/// `GlobalConstDict` の全エントリを Rust ソースとして出力する。
42/// 要素型の StructDef が見つからない、bindings.rs に既存等の場合はスキップ。
43pub fn emit_static_arrays(
44    global_const_dict: &GlobalConstDict,
45    fields_dict: &FieldsDict,
46    rust_decl_dict: Option<&RustDeclDict>,
47    interner: &StringInterner,
48) -> EmittedStaticArrays {
49    let mut out = String::new();
50    let mut emitted_names: std::collections::HashSet<String> = std::collections::HashSet::new();
51    let mut emitted_types: std::collections::HashMap<String, String> = std::collections::HashMap::new();
52    let bindings_consts: std::collections::HashSet<String> = rust_decl_dict
53        .map(|d| d.consts.keys().cloned().collect())
54        .unwrap_or_default();
55
56    let mut entries: Vec<(InternedStr, &GlobalConstDecl)> = global_const_dict
57        .iter()
58        .map(|(n, d)| (*n, d))
59        .collect();
60    entries.sort_by(|a, b| interner.get(a.0).cmp(interner.get(b.0)));
61
62    let mut header_emitted = false;
63    for (name, decl) in entries {
64        let name_str = interner.get(name);
65        // bindings.rs に同名 const があればスキップ
66        if bindings_consts.contains(name_str) {
67            continue;
68        }
69        // 要素型から struct 名を解決
70        let struct_name = match decl.element_type.type_name() {
71            Some(n) => n,
72            None => continue,
73        };
74        let struct_def = match fields_dict.get_struct_def(struct_name) {
75            Some(d) => d,
76            None => continue,  // 構造体定義が無ければ翻訳不可
77        };
78        let result = emit_one_array(name_str, decl, struct_def, interner);
79        match result {
80            Ok(s) => {
81                if !header_emitted {
82                    out.push_str("// === Auto-generated static const arrays ===\n");
83                    out.push_str("// `static const X NAME[] = {...}` declarations from C headers,\n");
84                    out.push_str("// translated to Rust `static` so that referencing inline functions/macros\n");
85                    out.push_str("// can resolve them. Each entry's expression is translated using\n");
86                    out.push_str("// core::mem::{size_of,offset_of,size_of_val_raw}.\n\n");
87                    header_emitted = true;
88                }
89                out.push_str(&s);
90                out.push('\n');
91                emitted_names.insert(name_str.to_string());
92                let elem_str = decl.element_type.to_rust_string(interner);
93                let count = match &decl.initializer {
94                    Initializer::List(items) => items.len(),
95                    _ => 0,
96                };
97                emitted_types.insert(
98                    name_str.to_string(),
99                    format!("[{}; {}]", elem_str, count),
100                );
101            }
102            Err(reason) => {
103                if !header_emitted {
104                    out.push_str("// === Auto-generated static const arrays ===\n\n");
105                    header_emitted = true;
106                }
107                out.push_str(&format!(
108                    "// [SKIPPED] static {} — {}\n\n", name_str, reason
109                ));
110            }
111        }
112    }
113    EmittedStaticArrays { source: out, emitted_names, emitted_types }
114}
115
116fn emit_one_array(
117    name: &str,
118    decl: &GlobalConstDecl,
119    struct_def: &StructDef,
120    interner: &StringInterner,
121) -> Result<String, String> {
122    let items = match &decl.initializer {
123        Initializer::List(items) => items,
124        _ => return Err("initializer is not a list".into()),
125    };
126    let elem_type_str = decl.element_type.to_rust_string(interner);
127    let count = items.len();
128
129    // 各エントリの内側 Initializer も List のはず
130    let mut entries_rust: Vec<String> = Vec::new();
131    for (idx, item) in items.iter().enumerate() {
132        match &item.init {
133            Initializer::List(inner) => {
134                let entry_str = build_struct_literal(
135                    &elem_type_str, struct_def, inner, interner,
136                ).map_err(|e| format!("entry [{}]: {}", idx, e))?;
137                entries_rust.push(entry_str);
138            }
139            Initializer::Expr(_) => return Err(format!("entry [{}] is not a compound", idx)),
140        }
141    }
142
143    let mut out = String::new();
144    out.push_str(&format!(
145        "#[allow(non_upper_case_globals)]\n\
146         pub static {}: [{}; {}] = [\n",
147        name, elem_type_str, count
148    ));
149    for (i, e) in entries_rust.iter().enumerate() {
150        out.push_str(&format!("    /* [{}] */ {},\n", i, e));
151    }
152    out.push_str("];\n");
153    Ok(out)
154}
155
156/// 1 つの struct literal を組み立てる。
157/// inner は `{ a, b, c, ... }` の各値の InitializerItem 列。
158/// struct_def のフィールド順に対応付け、bitfield 連続グループは pack する。
159fn build_struct_literal(
160    type_str: &str,
161    struct_def: &StructDef,
162    inner: &[crate::ast::InitializerItem],
163    interner: &StringInterner,
164) -> Result<String, String> {
165    // 値式を順に取り出す
166    let values: Vec<&Expr> = inner.iter().filter_map(|ii| match &ii.init {
167        Initializer::Expr(e) => Some(e.as_ref()),
168        _ => None,
169    }).collect();
170
171    let mut field_strs: Vec<String> = Vec::new();
172    let mut value_idx = 0usize;
173    let mut i = 0usize;
174    let mut bitfield_group_idx = 0usize;
175    while i < struct_def.members.len() {
176        let m = &struct_def.members[i];
177        if m.bitfield_width.is_some() {
178            // bitfield グループ全体の値を pack
179            let group_start = i;
180            let mut total_width = 0u32;
181            let mut group_widths: Vec<u32> = Vec::new();
182            while i < struct_def.members.len() && struct_def.members[i].bitfield_width.is_some() {
183                let w = struct_def.members[i].bitfield_width.unwrap();
184                group_widths.push(w);
185                total_width += w;
186                i += 1;
187            }
188            let pack_ty = if total_width <= 8 { "u8" }
189                else if total_width <= 16 { "u16" }
190                else if total_width <= 32 { "u32" }
191                else { "u64" };
192            // group_widths.len() 個の値を取り出して pack
193            if value_idx + group_widths.len() > values.len() {
194                return Err(format!("not enough initializer values for bitfield group at member {}",
195                    interner.get(struct_def.members[group_start].name)));
196            }
197            let mut shift = 0u32;
198            let mut parts: Vec<String> = Vec::new();
199            for (gi, w) in group_widths.iter().enumerate() {
200                let val_expr = values[value_idx + gi];
201                let val_rust = translate_const_expr(val_expr, interner);
202                let mask = (1u64 << w) - 1;
203                let part = format!("(({}) as {} & {:#x}) << {}",
204                    val_rust, pack_ty, mask, shift);
205                parts.push(crate::syn_codegen::normalize_parens(&part));
206                shift += w;
207            }
208            field_strs.push(format!("_bitfield_{}: {}",
209                bitfield_group_idx,
210                parts.join(" | ")));
211            bitfield_group_idx += 1;
212            value_idx += group_widths.len();
213        } else {
214            // 通常フィールド
215            if value_idx >= values.len() {
216                return Err(format!("not enough initializer values for member {}",
217                    interner.get(m.name)));
218            }
219            let val_expr = values[value_idx];
220            let mut val_rust = translate_const_expr(val_expr, interner);
221            let target_ty = m.type_repr.to_rust_string(interner);
222            if is_integer_target(&target_ty) {
223                val_rust = format!("({}) as {}", val_rust, target_ty);
224            }
225            let val_rust = crate::syn_codegen::normalize_parens(&val_rust);
226            field_strs.push(format!("{}: {}", interner.get(m.name), val_rust));
227            value_idx += 1;
228            i += 1;
229        }
230    }
231
232    if value_idx < values.len() {
233        return Err(format!("excess initializer values: {} > {}", values.len(), value_idx));
234    }
235
236    Ok(format!("{} {{ {} }}", type_str, field_strs.join(", ")))
237}
238
239fn is_integer_target(ty: &str) -> bool {
240    matches!(ty,
241        "u8" | "u16" | "u32" | "u64" | "u128" | "usize" |
242        "i8" | "i16" | "i32" | "i64" | "i128" | "isize" |
243        "U8" | "U16" | "U32" | "U64" | "I8" | "I16" | "I32" | "I64" |
244        "IV" | "UV" | "STRLEN" | "Size_t" | "SSize_t" | "ssize_t" | "size_t")
245}
246
247/// 純粋な C const 式を Rust に翻訳する。
248/// `+`, `-`, `*`, `?:`, `cast`, `sizeof`, `__builtin_offsetof`, ident, intlit
249/// などを扱う。値そのものは **const-eval 可能な Rust 式**を返す。
250fn translate_const_expr(expr: &Expr, interner: &StringInterner) -> String {
251    match &expr.kind {
252        ExprKind::IntLit(n) => format!("{}", n),
253        ExprKind::UIntLit(n) => format!("{}", n),
254        ExprKind::Ident(name) => {
255            // 既知の C 由来 enum/const はそのまま使う(bindings.rs に存在前提)
256            interner.get(*name).to_string()
257        }
258        ExprKind::SizeofType(tn) => {
259            let t = type_name_to_rust(tn, interner);
260            format!("core::mem::size_of::<{}>()", t)
261        }
262        ExprKind::Sizeof(inner) => {
263            // sizeof(expr) を const-eval 可能な形に翻訳。
264            // copy_length(T, m) 展開時の典型形 `((T*)X)->field_chain` に
265            // 限定して `core::mem::size_of_val(&core::mem::zeroed::<T>().field_chain)`
266            // を生成する。core::mem::zeroed と size_of_val は const-stable
267            // (Rust 1.75 / 1.85)。
268            if let Some((type_name, field_path)) = match_sizeof_field_pattern(inner, interner) {
269                // 一時値の lifetime 問題(E0716)回避のため let 束縛してから
270                // 参照を取る。union field アクセスを含む可能性があるため
271                // 全体を unsafe block で包む。
272                format!(
273                    "{{ let _z = unsafe {{ core::mem::zeroed::<{}>() }}; \
274                     core::mem::size_of_val(unsafe {{ &_z.{} }}) }}",
275                    type_name, field_path
276                )
277            } else {
278                let inner_rust = translate_const_expr(inner, interner);
279                // フォールバック: 配列/プリミティブの場合は size_of_val
280                format!(
281                    "core::mem::size_of_val(&{{ {} }})",
282                    inner_rust
283                )
284            }
285        }
286        ExprKind::BuiltinCall { name, args } => {
287            let func_name = interner.get(*name);
288            if matches!(func_name, "offsetof" | "__builtin_offsetof" | "STRUCT_OFFSET")
289                && args.len() == 2
290            {
291                let type_str = match &args[0] {
292                    BuiltinArg::TypeName(tn) => type_name_to_rust(tn, interner),
293                    BuiltinArg::Expr(e) => translate_const_expr(e, interner),
294                };
295                let field_path = match &args[1] {
296                    BuiltinArg::Expr(e) => expr_to_field_path(e, interner)
297                        .unwrap_or_else(|| translate_const_expr(e, interner)),
298                    _ => String::from("__UNRESOLVED_FIELD_PATH__"),
299                };
300                format!("core::mem::offset_of!({}, {})", type_str, field_path)
301            } else {
302                format!("__UNSUPPORTED_BUILTIN_{}__()", func_name)
303            }
304        }
305        ExprKind::Cast { type_name, expr: inner } => {
306            let t = type_name_to_rust(type_name, interner);
307            let inner_rust = translate_const_expr(inner, interner);
308            // ポインタターゲットの場合 raw pointer cast
309            if t.contains('*') {
310                format!("(({}) as {})", inner_rust, t)
311            } else {
312                format!("(({}) as {})", inner_rust, t)
313            }
314        }
315        ExprKind::Binary { op, lhs, rhs } => {
316            let l = translate_const_expr(lhs, interner);
317            let r = translate_const_expr(rhs, interner);
318            let op_str = bin_op_to_rust(op);
319            format!("({} {} {})", l, op_str, r)
320        }
321        ExprKind::UnaryPlus(inner) => translate_const_expr(inner, interner),
322        ExprKind::UnaryMinus(inner) => format!("-({})", translate_const_expr(inner, interner)),
323        ExprKind::Conditional { cond, then_expr, else_expr } => {
324            // C の `cond ? a : b` は値式。Rust 側は const if 式を使う。
325            // cond が比較式 (==, !=, <, <=, >, >=, &&, ||) なら既に bool なので
326            // そのまま使う。整数式なら `!= 0` で bool 化。
327            let c = translate_const_expr(cond, interner);
328            let t = translate_const_expr(then_expr, interner);
329            let e = translate_const_expr(else_expr, interner);
330            if is_bool_expr(cond) {
331                format!("(if ({}) {{ {} }} else {{ {} }})", c, t, e)
332            } else {
333                format!("(if ({}) != 0 {{ {} }} else {{ {} }})", c, t, e)
334            }
335        }
336        ExprKind::Member { expr: base, member } => {
337            let b = translate_const_expr(base, interner);
338            format!("({}.{})", b, interner.get(*member))
339        }
340        ExprKind::PtrMember { expr: base, member } => {
341            // a->b → (*a).b (place 式を維持。括弧は曖昧性回避用)
342            let b = translate_const_expr(base, interner);
343            format!("((*{}).{})", b, interner.get(*member))
344        }
345        ExprKind::Deref(inner) => {
346            let i = translate_const_expr(inner, interner);
347            format!("(*({}))", i)
348        }
349        // フォールバック
350        _ => format!("/* UNSUPPORTED EXPR: {:?} */ 0",
351                     std::mem::discriminant(&expr.kind)),
352    }
353}
354
355/// `cond ? a : b` の cond 部分が既に bool 値を返すか判定。
356/// Comparison/logical op の場合は true。
357fn is_bool_expr(expr: &Expr) -> bool {
358    use crate::ast::BinOp::*;
359    match &expr.kind {
360        ExprKind::Binary { op, .. } => matches!(op,
361            Lt | Gt | Le | Ge | Eq | Ne | LogAnd | LogOr),
362        ExprKind::LogNot(_) => true,
363        _ => false,
364    }
365}
366
367fn bin_op_to_rust(op: &crate::ast::BinOp) -> &'static str {
368    use crate::ast::BinOp::*;
369    match op {
370        Add => "+", Sub => "-", Mul => "*", Div => "/", Mod => "%",
371        Lt => "<", Gt => ">", Le => "<=", Ge => ">=",
372        Eq => "==", Ne => "!=",
373        BitAnd => "&", BitOr => "|", BitXor => "^",
374        Shl => "<<", Shr => ">>",
375        LogAnd => "&&", LogOr => "||",
376    }
377}
378
379fn type_name_to_rust(tn: &crate::ast::TypeName, interner: &StringInterner) -> String {
380    let repr = TypeRepr::from_type_name(tn, interner);
381    repr.to_rust_string(interner)
382}
383
384/// `((T*)X)->f1.f2` 形式の sizeof 引数を検出し、(T 名, f1.f2) を返す。
385/// `copy_length(T, last_member)` マクロ展開で典型的に現れる:
386/// `sizeof((T*)SvANY((const SV*)0))->last_member))` のような形。
387fn match_sizeof_field_pattern(
388    expr: &Expr,
389    interner: &StringInterner,
390) -> Option<(String, String)> {
391    // outer は Member { base, member } か PtrMember { base, member }
392    // base を辿って最終的に Cast { type_name: T*, .. } に到達するまで field path を蓄積
393    let mut path: Vec<String> = Vec::new();
394    let mut cur = expr;
395    loop {
396        match &cur.kind {
397            ExprKind::Member { expr: base, member }
398            | ExprKind::PtrMember { expr: base, member } => {
399                path.push(interner.get(*member).to_string());
400                cur = base;
401            }
402            ExprKind::Cast { type_name, expr: _ } => {
403                // type_name の派生にポインタが 1 つあれば、その指す型を返す
404                let has_ptr = type_name
405                    .declarator
406                    .as_ref()
407                    .map(|d| d.derived.iter().any(|x| matches!(x, crate::ast::DerivedDecl::Pointer(_))))
408                    .unwrap_or(false);
409                if has_ptr {
410                    let mut tn_no_ptr = (**type_name).clone();
411                    if let Some(d) = tn_no_ptr.declarator.as_mut() {
412                        d.derived.retain(|x| !matches!(x, crate::ast::DerivedDecl::Pointer(_)));
413                    }
414                    let type_str = type_name_to_rust(&tn_no_ptr, interner);
415                    if path.is_empty() { return None; }
416                    path.reverse();
417                    return Some((type_str, path.join(".")));
418                }
419                return None;
420            }
421            _ => return None,
422        }
423    }
424}
425
426/// `xpv_len_u.xpvlenu_len` のような field path を文字列化(offset_of! 用)
427fn expr_to_field_path(expr: &Expr, interner: &StringInterner) -> Option<String> {
428    match &expr.kind {
429        ExprKind::Ident(name) => Some(interner.get(*name).to_string()),
430        ExprKind::Member { expr: base, member } => {
431            let b = expr_to_field_path(base, interner)?;
432            Some(format!("{}.{}", b, interner.get(*member)))
433        }
434        ExprKind::PtrMember { expr: base, member } => {
435            // C `a->b` を offset_of の field path として「a.b」に正規化(パーサ側で
436            // anonymous union 等を扱う場合の想定)
437            let b = expr_to_field_path(base, interner)?;
438            Some(format!("{}.{}", b, interner.get(*member)))
439        }
440        _ => None,
441    }
442}