Coverage Report

Created: 2025-09-05 15: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
55
    pub fn try_transpile_type_conversion_refactored(
13
55
        &self, 
14
55
        base_name: &str, 
15
55
        args: &[Expr]
16
55
    ) -> Result<Option<TokenStream>> {
17
        // Only check known type conversion functions
18
55
        match base_name {
19
55
            "str" | 
"int"48
|
"float"41
|
"bool"36
|
"list"27
|
"set"23
|
"dict"20
=> {
20
                // These functions require exactly 1 argument
21
38
                if args.len() != 1 {
22
1
                    bail!("{base_name}() expects exactly 1 argument");
23
37
                }
24
            }
25
17
            _ => return Ok(None), // Not a type conversion, don't validate
26
        }
27
        
28
37
        match base_name {
29
37
            "str" => 
self7
.
convert_to_string7
(
&args[0]7
),
30
30
            "int" => 
self6
.
convert_to_int6
(
&args[0]6
),
31
24
            "float" => 
self5
.
convert_to_float5
(
&args[0]5
),
32
19
            "bool" => 
self9
.
convert_to_bool9
(
&args[0]9
),
33
10
            "list" => 
self4
.
convert_to_list4
(
&args[0]4
),
34
6
            "set" => 
self3
.
convert_to_set3
(
&args[0]3
),
35
3
            "dict" => self.convert_to_dict(&args[0]),
36
0
            _ => Ok(None), // Not a type conversion
37
        }
38
55
    }
39
    
40
    /// Convert to string (complexity: 3)
41
7
    fn convert_to_string(&self, arg: &Expr) -> Result<Option<TokenStream>> {
42
7
        let value = self.transpile_expr(arg)
?0
;
43
7
        Ok(Some(quote! { format!("{}", #value) }))
44
7
    }
45
    
46
    /// Convert to integer (complexity: 12)
47
6
    fn convert_to_int(&self, arg: &Expr) -> Result<Option<TokenStream>> {
48
6
        match &arg.kind {
49
            // String literal -> parse
50
            ExprKind::Literal(Literal::String(_)) => {
51
2
                let value = self.transpile_expr(arg)
?0
;
52
2
                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
2
                let value = self.transpile_expr(arg)
?0
;
62
2
                Ok(Some(quote! { (#value as i64) }))
63
            }
64
            // Bool literal -> 0 or 1
65
            ExprKind::Literal(Literal::Bool(_)) => {
66
1
                let value = self.transpile_expr(arg)
?0
;
67
1
                Ok(Some(quote! { if #value { 1i64 } else { 0i64 } }))
68
            }
69
            // Default: runtime cast
70
            _ => {
71
1
                let value = self.transpile_expr(arg)
?0
;
72
1
                Ok(Some(quote! { (#value as i64) }))
73
            }
74
        }
75
6
    }
76
    
77
    /// Convert to float (complexity: 10)
78
5
    fn convert_to_float(&self, arg: &Expr) -> Result<Option<TokenStream>> {
79
5
        match &arg.kind {
80
            // String literal -> parse
81
            ExprKind::Literal(Literal::String(_)) => {
82
2
                let value = self.transpile_expr(arg)
?0
;
83
2
                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
3
                let value = self.transpile_expr(arg)
?0
;
93
3
                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
5
    }
102
    
103
    /// Convert to bool (complexity: ~10)
104
9
    fn convert_to_bool(&self, arg: &Expr) -> Result<Option<TokenStream>> {
105
        // Delegate to specific bool conversion based on literal type
106
9
        match &arg.kind {
107
7
            ExprKind::Literal(lit) => self.convert_literal_to_bool(lit, arg),
108
1
            ExprKind::StringInterpolation { .. } => self.convert_string_to_bool(arg),
109
1
            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
9
    }
114
    
115
    /// Convert literal to bool (complexity: ~8)
116
7
    fn convert_literal_to_bool(&self, lit: &Literal, arg: &Expr) -> Result<Option<TokenStream>> {
117
7
        match lit {
118
            Literal::Integer(_) => {
119
4
                let value = self.transpile_expr(arg)
?0
;
120
4
                Ok(Some(quote! { (#value != 0) }))
121
            }
122
            Literal::String(_) => {
123
3
                let value = self.transpile_expr(arg)
?0
;
124
3
                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
7
    }
133
    
134
    /// Convert string to bool (complexity: 3)
135
1
    fn convert_string_to_bool(&self, arg: &Expr) -> Result<Option<TokenStream>> {
136
1
        let value = self.transpile_expr(arg)
?0
;
137
1
        Ok(Some(quote! { !#value.is_empty() }))
138
1
    }
139
    
140
    /// Convert collection to bool (complexity: 3)
141
1
    fn convert_collection_to_bool(&self, arg: &Expr) -> Result<Option<TokenStream>> {
142
1
        let value = self.transpile_expr(arg)
?0
;
143
1
        Ok(Some(quote! { !#value.is_empty() }))
144
1
    }
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
4
    fn convert_to_list(&self, arg: &Expr) -> Result<Option<TokenStream>> {
162
3
        match &arg.kind {
163
            // String -> chars as list
164
            ExprKind::Literal(Literal::String(_)) => {
165
2
                let value = self.transpile_expr(arg)
?0
;
166
2
                Ok(Some(quote! { #value.chars().map(|c| c.to_string()).collect::<Vec<_>>() }))
167
            }
168
            // Range -> collect to vec
169
            ExprKind::Range { .. } => {
170
1
                let value = self.transpile_expr(arg)
?0
;
171
1
                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
1
                let value = self.transpile_expr(arg)
?0
;
181
1
                Ok(Some(quote! { vec![#value] }))
182
            }
183
        }
184
4
    }
185
    
186
    /// Convert to set (complexity: 8)
187
3
    fn convert_to_set(&self, arg: &Expr) -> Result<Option<TokenStream>> {
188
1
        match &arg.kind {
189
            // List -> convert to HashSet
190
            ExprKind::List(_) => {
191
2
                let value = self.transpile_expr(arg)
?0
;
192
2
                Ok(Some(quote! { 
193
2
                    #value.into_iter().collect::<std::collections::HashSet<_>>() 
194
2
                }))
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
1
                let value = self.transpile_expr(arg)
?0
;
207
1
                Ok(Some(quote! { 
208
1
                    {
209
1
                        let mut set = std::collections::HashSet::new();
210
1
                        set.insert(#value);
211
1
                        set
212
1
                    }
213
1
                }))
214
            }
215
        }
216
3
    }
217
    
218
    /// Convert to dict (complexity: 6)
219
3
    fn convert_to_dict(&self, arg: &Expr) -> Result<Option<TokenStream>> {
220
2
        match &arg.kind {
221
            // List of tuples -> dict
222
2
            ExprKind::List(items) if items.iter().all(is_tuple_expr) => {
223
2
                let value = self.transpile_expr(arg)
?0
;
224
2
                Ok(Some(quote! { 
225
2
                    #value.into_iter()
226
2
                        .map(|(k, v)| (k, v))
227
2
                        .collect::<std::collections::HashMap<_, _>>() 
228
2
                }))
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
1
                Ok(Some(quote! { std::collections::HashMap::new() }))
240
            }
241
        }
242
3
    }
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
1
fn is_tuple_expr(expr: &Expr) -> bool {
252
1
    matches!(&expr.kind, ExprKind::Tuple(items) if items.len() == 2)
253
1
}
254
255
#[cfg(test)]
256
#[path = "type_conversion_refactored_tests.rs"]
257
mod tests;