Skip to main content

libperl_macrogen/
macro_def.rs

1//! マクロ定義と管理
2//!
3//! Cプリプロセッサのマクロ定義を表現し、マクロテーブルで管理する。
4
5use std::collections::HashMap;
6
7use crate::intern::InternedStr;
8use crate::source::SourceLocation;
9use crate::token::{Comment, Token, TokenKind};
10
11/// マクロ定義の種類
12#[derive(Debug, Clone, PartialEq)]
13pub enum MacroKind {
14    /// オブジェクトマクロ: #define FOO value
15    Object,
16    /// 関数マクロ: #define FOO(a, b) ...
17    Function {
18        params: Vec<InternedStr>,
19        is_variadic: bool,
20    },
21}
22
23/// マクロ定義
24#[derive(Debug, Clone)]
25pub struct MacroDef {
26    /// マクロ名
27    pub name: InternedStr,
28    /// マクロの種類
29    pub kind: MacroKind,
30    /// 置換トークン列
31    pub body: Vec<Token>,
32    /// 定義された位置(ファイル追跡用)
33    pub def_loc: SourceLocation,
34    /// 定義前のコメント(将来のドキュメント生成用)
35    pub leading_comments: Vec<Comment>,
36    /// ビルトインマクロかどうか
37    pub is_builtin: bool,
38    /// ターゲットディレクトリで定義されたマクロかどうか
39    pub is_target: bool,
40    /// マクロ本体にトークン連結 (##) を含むか
41    pub has_token_pasting: bool,
42}
43
44impl MacroDef {
45    /// 新しいオブジェクトマクロを作成
46    pub fn object(
47        name: InternedStr,
48        body: Vec<Token>,
49        def_loc: SourceLocation,
50    ) -> Self {
51        let has_token_pasting = body.iter()
52            .any(|t| matches!(t.kind, TokenKind::HashHash));
53        Self {
54            name,
55            kind: MacroKind::Object,
56            body,
57            def_loc,
58            leading_comments: Vec::new(),
59            is_builtin: false,
60            is_target: false,
61            has_token_pasting,
62        }
63    }
64
65    /// 新しい関数マクロを作成
66    pub fn function(
67        name: InternedStr,
68        params: Vec<InternedStr>,
69        is_variadic: bool,
70        body: Vec<Token>,
71        def_loc: SourceLocation,
72    ) -> Self {
73        let has_token_pasting = body.iter()
74            .any(|t| matches!(t.kind, TokenKind::HashHash));
75        Self {
76            name,
77            kind: MacroKind::Function { params, is_variadic },
78            body,
79            def_loc,
80            leading_comments: Vec::new(),
81            is_builtin: false,
82            is_target: false,
83            has_token_pasting,
84        }
85    }
86
87    /// ターゲットディレクトリのマクロとして設定
88    pub fn with_target(mut self, is_target: bool) -> Self {
89        self.is_target = is_target;
90        self
91    }
92
93    /// コメント付きで作成
94    pub fn with_comments(mut self, comments: Vec<Comment>) -> Self {
95        self.leading_comments = comments;
96        self
97    }
98
99    /// ビルトインとしてマーク
100    pub fn as_builtin(mut self) -> Self {
101        self.is_builtin = true;
102        self
103    }
104
105    /// 関数マクロかどうか
106    pub fn is_function(&self) -> bool {
107        matches!(self.kind, MacroKind::Function { .. })
108    }
109
110    /// パラメータ数を取得(オブジェクトマクロなら0)
111    pub fn param_count(&self) -> usize {
112        match &self.kind {
113            MacroKind::Object => 0,
114            MacroKind::Function { params, .. } => params.len(),
115        }
116    }
117
118    /// 可変引数マクロかどうか
119    pub fn is_variadic(&self) -> bool {
120        matches!(self.kind, MacroKind::Function { is_variadic: true, .. })
121    }
122}
123
124/// マクロテーブル
125#[derive(Debug, Default)]
126pub struct MacroTable {
127    macros: HashMap<InternedStr, MacroDef>,
128}
129
130impl MacroTable {
131    /// 新しいマクロテーブルを作成
132    pub fn new() -> Self {
133        Self {
134            macros: HashMap::new(),
135        }
136    }
137
138    /// マクロを定義(既存の定義があれば返す)
139    /// `__` で始まる builtin マクロは上書きされない
140    pub fn define(&mut self, def: MacroDef, interner: &crate::intern::StringInterner) -> Option<MacroDef> {
141        // 既存のマクロがbuiltinで、名前が __ で始まる場合は上書きしない
142        if let Some(existing) = self.macros.get(&def.name) {
143            if existing.is_builtin {
144                let name_str = interner.get(def.name);
145                if name_str.starts_with("__") {
146                    return None;
147                }
148            }
149        }
150        self.macros.insert(def.name, def)
151    }
152
153    /// マクロを削除(削除された定義があれば返す)
154    pub fn undefine(&mut self, name: InternedStr) -> Option<MacroDef> {
155        self.macros.remove(&name)
156    }
157
158    /// マクロ定義を取得
159    pub fn get(&self, name: InternedStr) -> Option<&MacroDef> {
160        self.macros.get(&name)
161    }
162
163    /// マクロが定義されているかどうか
164    pub fn is_defined(&self, name: InternedStr) -> bool {
165        self.macros.contains_key(&name)
166    }
167
168    /// 全マクロをイテレート
169    pub fn iter(&self) -> impl Iterator<Item = (&InternedStr, &MacroDef)> {
170        self.macros.iter()
171    }
172
173    /// ターゲットマクロのみをイテレート
174    pub fn iter_target_macros(&self) -> impl Iterator<Item = &MacroDef> {
175        self.macros.values().filter(|def| def.is_target)
176    }
177
178    /// マクロ数を返す
179    pub fn len(&self) -> usize {
180        self.macros.len()
181    }
182
183    /// テーブルが空かどうか
184    pub fn is_empty(&self) -> bool {
185        self.macros.is_empty()
186    }
187
188    /// 非ビルトインマクロのみをイテレート
189    pub fn user_defined(&self) -> impl Iterator<Item = (&InternedStr, &MacroDef)> {
190        self.macros.iter().filter(|(_, def)| !def.is_builtin)
191    }
192
193    /// 特定のマクロを検索してダンプ(デバッグ用)
194    ///
195    /// `filter` に含まれる文字列を名前に持つマクロを表示。
196    /// `filter` が空の場合は全マクロを表示。
197    pub fn dump_filtered(&self, filter: &str, interner: &crate::intern::StringInterner) {
198        let mut names: Vec<_> = self.macros.keys().collect();
199        names.sort_by_key(|id| interner.get(**id));
200
201        for &name in &names {
202            let name_str = interner.get(*name);
203            if !filter.is_empty() && !name_str.contains(filter) {
204                continue;
205            }
206
207            if let Some(def) = self.macros.get(name) {
208                let kind_str = match &def.kind {
209                    MacroKind::Object => "object".to_string(),
210                    MacroKind::Function { params, is_variadic } => {
211                        let params_str: Vec<_> = params.iter()
212                            .map(|p| interner.get(*p).to_string())
213                            .collect();
214                        if *is_variadic {
215                            format!("function({}...)", params_str.join(", "))
216                        } else {
217                            format!("function({})", params_str.join(", "))
218                        }
219                    }
220                };
221
222                let body_str: String = def.body.iter()
223                    .map(|t| t.kind.format(interner))
224                    .collect::<Vec<_>>()
225                    .join(" ");
226
227                let flags = format!(
228                    "{}{}",
229                    if def.is_target { "T" } else { "" },
230                    if def.is_builtin { "B" } else { "" },
231                );
232
233                println!("#define {} [{}] {} = {}",
234                    name_str,
235                    kind_str,
236                    if flags.is_empty() { "".to_string() } else { format!("({})", flags) },
237                    body_str
238                );
239            }
240        }
241    }
242}
243
244#[cfg(test)]
245mod tests {
246    use super::*;
247    use crate::intern::StringInterner;
248    use crate::source::FileId;
249
250    #[test]
251    fn test_object_macro() {
252        let mut interner = StringInterner::new();
253        let name = interner.intern("FOO");
254        let loc = SourceLocation::new(FileId::default(), 1, 1);
255
256        let def = MacroDef::object(name, vec![], loc);
257        assert!(!def.is_function());
258        assert_eq!(def.param_count(), 0);
259        assert!(!def.is_variadic());
260    }
261
262    #[test]
263    fn test_function_macro() {
264        let mut interner = StringInterner::new();
265        let name = interner.intern("MAX");
266        let a = interner.intern("a");
267        let b = interner.intern("b");
268        let loc = SourceLocation::new(FileId::default(), 1, 1);
269
270        let def = MacroDef::function(name, vec![a, b], false, vec![], loc);
271        assert!(def.is_function());
272        assert_eq!(def.param_count(), 2);
273        assert!(!def.is_variadic());
274    }
275
276    #[test]
277    fn test_variadic_macro() {
278        let mut interner = StringInterner::new();
279        let name = interner.intern("PRINTF");
280        let fmt = interner.intern("fmt");
281        let loc = SourceLocation::new(FileId::default(), 1, 1);
282
283        let def = MacroDef::function(name, vec![fmt], true, vec![], loc);
284        assert!(def.is_function());
285        assert!(def.is_variadic());
286    }
287
288    #[test]
289    fn test_macro_table() {
290        let mut interner = StringInterner::new();
291        let mut table = MacroTable::new();
292
293        let foo = interner.intern("FOO");
294        let bar = interner.intern("BAR");
295        let loc = SourceLocation::new(FileId::default(), 1, 1);
296
297        // 定義
298        assert!(table.define(MacroDef::object(foo, vec![], loc.clone()), &interner).is_none());
299        assert!(table.define(MacroDef::object(bar, vec![], loc.clone()), &interner).is_none());
300        assert_eq!(table.len(), 2);
301
302        // 検索
303        assert!(table.is_defined(foo));
304        assert!(table.get(foo).is_some());
305
306        // 再定義
307        let old = table.define(MacroDef::object(foo, vec![], loc), &interner);
308        assert!(old.is_some());
309        assert_eq!(table.len(), 2);
310
311        // 削除
312        assert!(table.undefine(foo).is_some());
313        assert!(!table.is_defined(foo));
314        assert_eq!(table.len(), 1);
315    }
316}