Coverage Report

Created: 2025-09-08 21:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/noah/src/ruchy/src/backend/transpiler/type_conversion_refactored.rs
Line
Count
Source
1
//! Refactored type conversion with reduced complexity
2
//! Original complexity: 62, Target: <20 per function
3
4
use crate::backend::Transpiler;
5
use crate::frontend::ast::{Expr, ExprKind, Literal, StringPart};
6
use anyhow::{bail, Result};
7
use proc_macro2::TokenStream;
8
use quote::quote;
9
10
impl Transpiler {
11
    /// Main dispatcher for type conversion (complexity: ~8)
12
0
    pub fn try_transpile_type_conversion_refactored(
13
0
        &self, 
14
0
        base_name: &str, 
15
0
        args: &[Expr]
16
0
    ) -> Result<Option<TokenStream>> {
17
        // Only check known type conversion functions
18
0
        match base_name {
19
0
            "str" | "int" | "float" | "bool" | "list" | "set" | "dict" => {
20
                // These functions require exactly 1 argument
21
0
                if args.len() != 1 {
22
0
                    bail!("{base_name}() expects exactly 1 argument");
23
0
                }
24
            }
25
0
            _ => return Ok(None), // Not a type conversion, don't validate
26
        }
27
        
28
0
        match base_name {
29
0
            "str" => self.convert_to_string(&args[0]),
30
0
            "int" => self.convert_to_int(&args[0]),
31
0
            "float" => self.convert_to_float(&args[0]),
32
0
            "bool" => self.convert_to_bool(&args[0]),
33
0
            "list" => self.convert_to_list(&args[0]),
34
0
            "set" => self.convert_to_set(&args[0]),
35
0
            "dict" => self.convert_to_dict(&args[0]),
36
0
            _ => Ok(None), // Not a type conversion
37
        }
38
0
    }
39
    
40
    /// Convert to string (complexity: 3)
41
0
    fn convert_to_string(&self, arg: &Expr) -> Result<Option<TokenStream>> {
42
0
        let value = self.transpile_expr(arg)?;
43
0
        Ok(Some(quote! { format!("{}", #value) }))
44
0
    }
45
    
46
    /// Convert to integer (complexity: 12)
47
0
    fn convert_to_int(&self, arg: &Expr) -> Result<Option<TokenStream>> {
48
0
        match &arg.kind {
49
            // String literal -> parse
50
            ExprKind::Literal(Literal::String(_)) => {
51
0
                let value = self.transpile_expr(arg)?;
52
0
                Ok(Some(quote! { #value.parse::<i64>().expect("Failed to parse integer") }))
53
            }
54
            // String interpolation with single text part -> parse
55
0
            ExprKind::StringInterpolation { parts } if is_single_text_part(parts) => {
56
0
                let value = self.transpile_expr(arg)?;
57
0
                Ok(Some(quote! { #value.parse::<i64>().expect("Failed to parse integer") }))
58
            }
59
            // Float literal -> cast
60
            ExprKind::Literal(Literal::Float(_)) => {
61
0
                let value = self.transpile_expr(arg)?;
62
0
                Ok(Some(quote! { (#value as i64) }))
63
            }
64
            // Bool literal -> 0 or 1
65
            ExprKind::Literal(Literal::Bool(_)) => {
66
0
                let value = self.transpile_expr(arg)?;
67
0
                Ok(Some(quote! { if #value { 1i64 } else { 0i64 } }))
68
            }
69
            // Default: runtime cast
70
            _ => {
71
0
                let value = self.transpile_expr(arg)?;
72
0
                Ok(Some(quote! { (#value as i64) }))
73
            }
74
        }
75
0
    }
76
    
77
    /// Convert to float (complexity: 10)
78
0
    fn convert_to_float(&self, arg: &Expr) -> Result<Option<TokenStream>> {
79
0
        match &arg.kind {
80
            // String literal -> parse
81
            ExprKind::Literal(Literal::String(_)) => {
82
0
                let value = self.transpile_expr(arg)?;
83
0
                Ok(Some(quote! { #value.parse::<f64>().expect("Failed to parse float") }))
84
            }
85
            // String interpolation with single text part -> parse
86
0
            ExprKind::StringInterpolation { parts } if is_single_text_part(parts) => {
87
0
                let value = self.transpile_expr(arg)?;
88
0
                Ok(Some(quote! { #value.parse::<f64>().expect("Failed to parse float") }))
89
            }
90
            // Integer literal -> cast
91
            ExprKind::Literal(Literal::Integer(_)) => {
92
0
                let value = self.transpile_expr(arg)?;
93
0
                Ok(Some(quote! { (#value as f64) }))
94
            }
95
            // Default: runtime cast
96
            _ => {
97
0
                let value = self.transpile_expr(arg)?;
98
0
                Ok(Some(quote! { (#value as f64) }))
99
            }
100
        }
101
0
    }
102
    
103
    /// Convert to bool (complexity: ~10)
104
0
    fn convert_to_bool(&self, arg: &Expr) -> Result<Option<TokenStream>> {
105
        // Delegate to specific bool conversion based on literal type
106
0
        match &arg.kind {
107
0
            ExprKind::Literal(lit) => self.convert_literal_to_bool(lit, arg),
108
0
            ExprKind::StringInterpolation { .. } => self.convert_string_to_bool(arg),
109
0
            ExprKind::List(_) => self.convert_collection_to_bool(arg),
110
0
            ExprKind::None => Ok(Some(quote! { false })),
111
0
            _ => self.convert_generic_to_bool(arg),
112
        }
113
0
    }
114
    
115
    /// Convert literal to bool (complexity: ~8)
116
0
    fn convert_literal_to_bool(&self, lit: &Literal, arg: &Expr) -> Result<Option<TokenStream>> {
117
0
        match lit {
118
            Literal::Integer(_) => {
119
0
                let value = self.transpile_expr(arg)?;
120
0
                Ok(Some(quote! { (#value != 0) }))
121
            }
122
            Literal::String(_) => {
123
0
                let value = self.transpile_expr(arg)?;
124
0
                Ok(Some(quote! { !#value.is_empty() }))
125
            }
126
            Literal::Bool(_) => {
127
0
                let value = self.transpile_expr(arg)?;
128
0
                Ok(Some(value))
129
            }
130
0
            _ => self.convert_generic_to_bool(arg),
131
        }
132
0
    }
133
    
134
    /// Convert string to bool (complexity: 3)
135
0
    fn convert_string_to_bool(&self, arg: &Expr) -> Result<Option<TokenStream>> {
136
0
        let value = self.transpile_expr(arg)?;
137
0
        Ok(Some(quote! { !#value.is_empty() }))
138
0
    }
139
    
140
    /// Convert collection to bool (complexity: 3)
141
0
    fn convert_collection_to_bool(&self, arg: &Expr) -> Result<Option<TokenStream>> {
142
0
        let value = self.transpile_expr(arg)?;
143
0
        Ok(Some(quote! { !#value.is_empty() }))
144
0
    }
145
    
146
    /// Generic truthiness check (complexity: 3)
147
0
    fn convert_generic_to_bool(&self, arg: &Expr) -> Result<Option<TokenStream>> {
148
0
        let value = self.transpile_expr(arg)?;
149
0
        Ok(Some(quote! { 
150
0
            {
151
0
                // Generic truthiness check
152
0
                match &#value {
153
0
                    0 => false,
154
0
                    _ => true,
155
0
                }
156
0
            }
157
0
        }))
158
0
    }
159
    
160
    /// Convert to list (complexity: 8)
161
0
    fn convert_to_list(&self, arg: &Expr) -> Result<Option<TokenStream>> {
162
0
        match &arg.kind {
163
            // String -> chars as list
164
            ExprKind::Literal(Literal::String(_)) => {
165
0
                let value = self.transpile_expr(arg)?;
166
0
                Ok(Some(quote! { #value.chars().map(|c| c.to_string()).collect::<Vec<_>>() }))
167
            }
168
            // Range -> collect to vec
169
            ExprKind::Range { .. } => {
170
0
                let value = self.transpile_expr(arg)?;
171
0
                Ok(Some(quote! { #value.collect::<Vec<_>>() }))
172
            }
173
            // Tuple -> convert to vec
174
            ExprKind::Tuple(_) => {
175
0
                let value = self.transpile_expr(arg)?;
176
0
                Ok(Some(quote! { vec![#value] }))
177
            }
178
            // Default: wrap in vec
179
            _ => {
180
0
                let value = self.transpile_expr(arg)?;
181
0
                Ok(Some(quote! { vec![#value] }))
182
            }
183
        }
184
0
    }
185
    
186
    /// Convert to set (complexity: 8)
187
0
    fn convert_to_set(&self, arg: &Expr) -> Result<Option<TokenStream>> {
188
0
        match &arg.kind {
189
            // List -> convert to HashSet
190
            ExprKind::List(_) => {
191
0
                let value = self.transpile_expr(arg)?;
192
0
                Ok(Some(quote! { 
193
0
                    #value.into_iter().collect::<std::collections::HashSet<_>>() 
194
0
                }))
195
            }
196
            // String -> chars as set
197
            ExprKind::Literal(Literal::String(_)) => {
198
0
                let value = self.transpile_expr(arg)?;
199
0
                Ok(Some(quote! { 
200
0
                    #value.chars().map(|c| c.to_string())
201
0
                        .collect::<std::collections::HashSet<_>>() 
202
0
                }))
203
            }
204
            // Default: single element set
205
            _ => {
206
0
                let value = self.transpile_expr(arg)?;
207
0
                Ok(Some(quote! { 
208
0
                    {
209
0
                        let mut set = std::collections::HashSet::new();
210
0
                        set.insert(#value);
211
0
                        set
212
0
                    }
213
0
                }))
214
            }
215
        }
216
0
    }
217
    
218
    /// Convert to dict (complexity: 6)
219
0
    fn convert_to_dict(&self, arg: &Expr) -> Result<Option<TokenStream>> {
220
0
        match &arg.kind {
221
            // List of tuples -> dict
222
0
            ExprKind::List(items) if items.iter().all(is_tuple_expr) => {
223
0
                let value = self.transpile_expr(arg)?;
224
0
                Ok(Some(quote! { 
225
0
                    #value.into_iter()
226
0
                        .map(|(k, v)| (k, v))
227
0
                        .collect::<std::collections::HashMap<_, _>>() 
228
0
                }))
229
            }
230
            // ObjectLiteral -> convert to HashMap
231
            ExprKind::ObjectLiteral { .. } => {
232
0
                let value = self.transpile_expr(arg)?;
233
0
                Ok(Some(quote! { 
234
0
                    #value.into_iter().collect::<std::collections::HashMap<_, _>>() 
235
0
                }))
236
            }
237
            // Default: empty dict
238
            _ => {
239
0
                Ok(Some(quote! { std::collections::HashMap::new() }))
240
            }
241
        }
242
0
    }
243
}
244
245
// Helper functions (complexity: 1-3 each)
246
247
0
fn is_single_text_part(parts: &[StringPart]) -> bool {
248
0
    parts.len() == 1 && matches!(&parts[0], StringPart::Text(_))
249
0
}
250
251
0
fn is_tuple_expr(expr: &Expr) -> bool {
252
0
    matches!(&expr.kind, ExprKind::Tuple(items) if items.len() == 2)
253
0
}
254
255
#[cfg(test)]
256
#[path = "type_conversion_refactored_tests.rs"]
257
mod tests;