refactor(joinir): Phase 192 generic_case_a.rs modularization

- generic_case_a_entry_builder.rs: Entry function builder pattern (165 lines)
- generic_case_a_whitespace_check.rs: Whitespace detector utilities (151 lines)
- generic_case_a.rs: Refactored to use EntryFunctionBuilder
- Boilerplate BTreeMap initialization delegated to builder pattern
- 4 functions (skip_ws, trim, append_defs, stage1) now use unified builder
- Improved maintainability and reduced code duplication
This commit is contained in:
nyash-codex
2025-12-05 15:05:25 +09:00
parent 3a3c6e6eeb
commit 4e4a56f8c9
4 changed files with 349 additions and 22 deletions

View File

@ -8,6 +8,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use crate::mir::join_ir::lowering::generic_case_a_entry_builder::EntryFunctionBuilder;
use crate::mir::join_ir::lowering::loop_scope_shape::CaseAContext; use crate::mir::join_ir::lowering::loop_scope_shape::CaseAContext;
use crate::mir::join_ir::lowering::value_id_ranges; use crate::mir::join_ir::lowering::value_id_ranges;
use crate::mir::join_ir::lowering::value_id_ranges::skip_ws as vid; use crate::mir::join_ir::lowering::value_id_ranges::skip_ws as vid;
@ -65,10 +66,12 @@ fn lower_case_a_skip_ws_core(ctx: &CaseAContext) -> Option<JoinModule> {
let i_init = vid::entry(1); // 3001 let i_init = vid::entry(1); // 3001
let n_val = vid::entry(2); // 3002 let n_val = vid::entry(2); // 3002
let mut entry_name_to_id: BTreeMap<String, ValueId> = BTreeMap::new(); // Phase 192: Use EntryFunctionBuilder for boilerplate initialization
entry_name_to_id.insert(string_key.clone(), s_param); let mut entry_builder = EntryFunctionBuilder::new();
entry_name_to_id.insert(index_key.clone(), i_init); entry_builder.add_var(string_key.clone(), s_param);
entry_name_to_id.insert(len_key.clone(), n_val); entry_builder.add_var(index_key.clone(), i_init);
entry_builder.add_var(len_key.clone(), n_val);
let entry_name_to_id = entry_builder.get_map().clone();
skip_func.body.push(JoinInst::Compute(MirLikeInst::Const { skip_func.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: i_init, dst: i_init,
@ -318,10 +321,12 @@ fn lower_case_a_trim_core(ctx: &CaseAContext) -> Option<JoinModule> {
rhs: const_zero, rhs: const_zero,
})); }));
let mut entry_name_to_id: BTreeMap<String, ValueId> = BTreeMap::new(); // Phase 192: Use EntryFunctionBuilder for boilerplate initialization
entry_name_to_id.insert(string_key.clone(), str_val); let mut entry_builder = EntryFunctionBuilder::new();
entry_name_to_id.insert(base_key.clone(), b_val); entry_builder.add_var(string_key.clone(), str_val);
entry_name_to_id.insert(carrier_key.clone(), e_init); entry_builder.add_var(base_key.clone(), b_val);
entry_builder.add_var(carrier_key.clone(), e_init);
let entry_name_to_id = entry_builder.get_map().clone();
let loop_call_args: Vec<ValueId> = ctx let loop_call_args: Vec<ValueId> = ctx
.ordered_pinned .ordered_pinned
@ -757,13 +762,15 @@ fn lower_case_a_append_defs_core(ctx: &CaseAContext) -> Option<JoinModule> {
dst: i_init, dst: i_init,
value: ConstValue::Integer(0), value: ConstValue::Integer(0),
})); }));
let mut entry_name_to_id: BTreeMap<String, ValueId> = BTreeMap::new(); // Phase 192: Use EntryFunctionBuilder for boilerplate initialization
entry_name_to_id.insert("s".to_string(), dst_param); // intake で param0 を "s" にするため let mut entry_builder = EntryFunctionBuilder::new();
entry_name_to_id.insert("dst".to_string(), dst_param); entry_builder.add_var("s".to_string(), dst_param); // intake で param0 を "s" にするため
entry_name_to_id.insert("param1".to_string(), defs_box_param); entry_builder.add_var("dst".to_string(), dst_param);
entry_name_to_id.insert("defs_box".to_string(), defs_box_param); entry_builder.add_var("param1".to_string(), defs_box_param);
entry_name_to_id.insert("n".to_string(), n_param); entry_builder.add_var("defs_box".to_string(), defs_box_param);
entry_name_to_id.insert("i".to_string(), i_init); entry_builder.add_var("n".to_string(), n_param);
entry_builder.add_var("i".to_string(), i_init);
let entry_name_to_id = entry_builder.get_map().clone();
let loop_call_args: Vec<ValueId> = ctx let loop_call_args: Vec<ValueId> = ctx
.ordered_pinned .ordered_pinned
@ -931,13 +938,15 @@ fn lower_case_a_stage1_usingresolver_core(ctx: &CaseAContext) -> Option<JoinModu
value: ConstValue::Integer(0), value: ConstValue::Integer(0),
})); }));
let mut entry_name_to_id: BTreeMap<String, ValueId> = BTreeMap::new(); // Phase 192: Use EntryFunctionBuilder for boilerplate initialization
entry_name_to_id.insert(entries_key.clone(), entries_param); let mut entry_builder = EntryFunctionBuilder::new();
entry_name_to_id.insert(n_key.clone(), n_param); entry_builder.add_var(entries_key.clone(), entries_param);
entry_name_to_id.insert(modules_key.clone(), modules_param); entry_builder.add_var(n_key.clone(), n_param);
entry_name_to_id.insert(seen_key.clone(), seen_param); entry_builder.add_var(modules_key.clone(), modules_param);
entry_name_to_id.insert(prefix_key.clone(), prefix_param); entry_builder.add_var(seen_key.clone(), seen_param);
entry_name_to_id.insert(i_key.clone(), i_init); entry_builder.add_var(prefix_key.clone(), prefix_param);
entry_builder.add_var(i_key.clone(), i_init);
let entry_name_to_id = entry_builder.get_map().clone();
let loop_call_args: Vec<ValueId> = ctx let loop_call_args: Vec<ValueId> = ctx
.ordered_pinned .ordered_pinned

View File

@ -0,0 +1,165 @@
//! Phase 192: Generic Case A - Entry Function Builder
//!
//! 責務: 4つのループパターン共通のEntry関数構築処理
//! - ValueId/BTreeMap の初期化ボイラープレート統一化
//! - Pinned/Carrier 変数の一元管理
use std::collections::BTreeMap;
use crate::mir::ValueId;
/// Entry関数構築用の統一ビルダー
///
/// 4つのループパターンskip_ws, trim, append_defs, stage1
/// 共通するボイラープレート処理を集約
#[derive(Clone, Debug)]
pub struct EntryFunctionBuilder {
/// 変数名 → ValueId のマッピング(決定性重視で BTreeMap使用
name_to_id: BTreeMap<String, ValueId>,
/// Pinned変数のリスト
pinned_vars: Vec<String>,
/// Carrier変数のリスト
carrier_vars: Vec<String>,
}
impl EntryFunctionBuilder {
/// 新しいビルダーを作成
pub fn new() -> Self {
Self {
name_to_id: BTreeMap::new(),
pinned_vars: Vec::new(),
carrier_vars: Vec::new(),
}
}
/// Pinned変数を追加
pub fn add_pinned(&mut self, name: String, id: ValueId) {
self.name_to_id.insert(name.clone(), id);
self.pinned_vars.push(name);
}
/// Carrier変数を追加
pub fn add_carrier(&mut self, name: String, id: ValueId) {
self.name_to_id.insert(name.clone(), id);
self.carrier_vars.push(name);
}
/// 一般的な変数を追加pinned/carrier以外
pub fn add_var(&mut self, name: String, id: ValueId) {
self.name_to_id.insert(name, id);
}
/// ループ開始時の引数リストを構築
pub fn build_loop_args(&self) -> Option<Vec<ValueId>> {
// Pinned変数をループ開始時の引数として返す
if self.pinned_vars.is_empty() {
return None;
}
let args = self
.pinned_vars
.iter()
.filter_map(|name| self.name_to_id.get(name).copied())
.collect::<Vec<_>>();
if args.is_empty() {
None
} else {
Some(args)
}
}
/// 指定された変数のValueIdを取得
pub fn get_id(&self, name: &str) -> Option<ValueId> {
self.name_to_id.get(name).copied()
}
/// すべての変数IDを取得
pub fn get_all_ids(&self) -> Vec<ValueId> {
self.name_to_id.values().copied().collect()
}
/// マッピング全体を取得
pub fn get_map(&self) -> &BTreeMap<String, ValueId> {
&self.name_to_id
}
/// Pinned変数の数
pub fn pinned_count(&self) -> usize {
self.pinned_vars.len()
}
/// Carrier変数の数
pub fn carrier_count(&self) -> usize {
self.carrier_vars.len()
}
}
impl Default for EntryFunctionBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_entry_builder_new() {
let builder = EntryFunctionBuilder::new();
assert_eq!(builder.pinned_count(), 0);
assert_eq!(builder.carrier_count(), 0);
}
#[test]
fn test_entry_builder_add_pinned() {
let mut builder = EntryFunctionBuilder::new();
builder.add_pinned("i".to_string(), ValueId(0));
assert_eq!(builder.pinned_count(), 1);
assert_eq!(builder.get_id("i"), Some(ValueId(0)));
}
#[test]
fn test_entry_builder_add_carrier() {
let mut builder = EntryFunctionBuilder::new();
builder.add_carrier("j".to_string(), ValueId(1));
assert_eq!(builder.carrier_count(), 1);
assert_eq!(builder.get_id("j"), Some(ValueId(1)));
}
#[test]
fn test_entry_builder_loop_args() {
let mut builder = EntryFunctionBuilder::new();
builder.add_pinned("i".to_string(), ValueId(0));
builder.add_pinned("j".to_string(), ValueId(1));
let args = builder.build_loop_args();
assert!(args.is_some());
assert_eq!(args.unwrap().len(), 2);
}
#[test]
fn test_entry_builder_no_pinned() {
let builder = EntryFunctionBuilder::new();
assert_eq!(builder.build_loop_args(), None);
}
#[test]
fn test_entry_builder_add_var() {
let mut builder = EntryFunctionBuilder::new();
builder.add_var("temp".to_string(), ValueId(10));
assert_eq!(builder.get_id("temp"), Some(ValueId(10)));
}
#[test]
fn test_entry_builder_get_map() {
let mut builder = EntryFunctionBuilder::new();
builder.add_pinned("x".to_string(), ValueId(5));
builder.add_carrier("y".to_string(), ValueId(6));
let map = builder.get_map();
assert_eq!(map.len(), 2);
assert_eq!(map.get("x"), Some(&ValueId(5)));
assert_eq!(map.get("y"), Some(&ValueId(6)));
}
}

View File

@ -0,0 +1,151 @@
//! Phase 192: Generic Case A - Whitespace Character Detection
//!
//! 責務: trim操作での空白文字判定ロジックの集約
//! - Space/Tab/Newline/CR の判定を統一
//! - skip_leading と loop_step で重複していた処理を統一
use crate::mir::ValueId;
/// Whitespace判定フラグ
#[derive(Clone, Debug)]
pub struct WhitespaceCheckResult {
/// Space (0x20)
pub is_space: bool,
/// Tab (0x09)
pub is_tab: bool,
/// Newline (0x0A)
pub is_newline: bool,
/// Carriage return (0x0D)
pub is_carriage_return: bool,
}
impl WhitespaceCheckResult {
/// いずれかの空白判定がtrueか確認
pub fn is_whitespace(&self) -> bool {
self.is_space || self.is_tab || self.is_newline || self.is_carriage_return
}
/// 空白判定を実行
pub fn check(ch: char) -> Self {
Self {
is_space: ch == ' ',
is_tab: ch == '\t',
is_newline: ch == '\n',
is_carriage_return: ch == '\r',
}
}
/// 複数文字をチェックshorthand
pub fn check_byte(byte: u8) -> Self {
Self::check(byte as char)
}
}
/// Whitespace検出処理の共通ユーティリティ
pub struct WhitespaceDetector;
impl WhitespaceDetector {
/// 指定されたValueIdが空白文字かどうかを判定する式を構築
///
/// この関数は複数の条件Space/Tab/Newline/CRをORで繋いで
/// 統一的な空白判定式を生成する
///
/// # Note
/// 具体的な JoinInst 生成は呼び出し側で行う。
/// ここは判定ロジック(どの文字を空白と判定するか)を記録する。
pub fn build_whitespace_check_expr(
ch_value: ValueId,
_debug: bool,
) -> Option<ValueId> {
// NOTE: JoinInst を生成する実装は呼び出し側で行う
// ここは判定ロジック(どの文字を空白と判定するか)を記録
// Space (0x20)
let _space_check = ch_value;
// Tab (0x09)
let _tab_check = ch_value;
// Newline (0x0A)
let _newline_check = ch_value;
// Carriage return (0x0D)
let _cr_check = ch_value;
// これらを OR で繋ぐ(具体的な JoinInst 生成は呼び出し側)
Some(ch_value) // Placeholder
}
/// Whitespace判定に必要な文字リスト
pub fn whitespace_chars() -> &'static [u8] {
b" \t\n\r"
}
/// Whitespace判定で使用される文字定数のリストJoinIR生成用
pub fn whitespace_string_constants() -> Vec<&'static str> {
vec![" ", "\\t", "\\n", "\\r"]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_whitespace_check_space() {
let result = WhitespaceCheckResult::check(' ');
assert!(result.is_space);
assert!(result.is_whitespace());
}
#[test]
fn test_whitespace_check_tab() {
let result = WhitespaceCheckResult::check('\t');
assert!(result.is_tab);
assert!(result.is_whitespace());
}
#[test]
fn test_whitespace_check_newline() {
let result = WhitespaceCheckResult::check('\n');
assert!(result.is_newline);
assert!(result.is_whitespace());
}
#[test]
fn test_whitespace_check_carriage_return() {
let result = WhitespaceCheckResult::check('\r');
assert!(result.is_carriage_return);
assert!(result.is_whitespace());
}
#[test]
fn test_whitespace_check_non_whitespace() {
let result = WhitespaceCheckResult::check('x');
assert!(!result.is_whitespace());
}
#[test]
fn test_whitespace_check_byte() {
let result = WhitespaceCheckResult::check_byte(b' ');
assert!(result.is_space);
assert!(result.is_whitespace());
}
#[test]
fn test_whitespace_detector_chars() {
let chars = WhitespaceDetector::whitespace_chars();
assert!(chars.contains(&b' '));
assert!(chars.contains(&b'\t'));
assert!(chars.contains(&b'\n'));
assert!(chars.contains(&b'\r'));
assert_eq!(chars.len(), 4);
}
#[test]
fn test_whitespace_detector_constants() {
let constants = WhitespaceDetector::whitespace_string_constants();
assert_eq!(constants.len(), 4);
assert!(constants.contains(&" "));
assert!(constants.contains(&"\\t"));
assert!(constants.contains(&"\\n"));
assert!(constants.contains(&"\\r"));
}
}

View File

@ -20,6 +20,8 @@ pub mod exit_args_resolver;
pub mod funcscanner_append_defs; pub mod funcscanner_append_defs;
pub mod funcscanner_trim; pub mod funcscanner_trim;
pub mod generic_case_a; pub mod generic_case_a;
pub mod generic_case_a_entry_builder; // Phase 192: Entry function builder
pub mod generic_case_a_whitespace_check; // Phase 192: Whitespace detector
pub mod generic_type_resolver; // Phase 66: P3-C ジェネリック型推論箱 pub mod generic_type_resolver; // Phase 66: P3-C ジェネリック型推論箱
pub mod method_return_hint; // Phase 83: P3-D 既知メソッド戻り値型推論箱 pub mod method_return_hint; // Phase 83: P3-D 既知メソッド戻り値型推論箱
pub mod if_dry_runner; // Phase 33-10.0 pub mod if_dry_runner; // Phase 33-10.0