/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; |