/home/noah/src/ruchy/src/backend/transpiler/dispatcher.rs
Line | Count | Source |
1 | | //! Dispatcher functions to reduce complexity in transpiler |
2 | | //! |
3 | | //! This module contains delegated transpilation functions to keep |
4 | | //! cyclomatic complexity below 10 for each function. |
5 | | |
6 | | use super::Transpiler; |
7 | | use crate::frontend::ast::{Expr, ExprKind, Literal}; |
8 | | use anyhow::{bail, Result}; |
9 | | use proc_macro2::TokenStream; |
10 | | use quote::{format_ident, quote}; |
11 | | |
12 | | impl Transpiler { |
13 | | /// Transpile basic expressions (literals, identifiers, strings) |
14 | 682 | pub(super) fn transpile_basic_expr(&self, expr: &Expr) -> Result<TokenStream> { |
15 | 682 | match &expr.kind { |
16 | 424 | ExprKind::Literal(lit) => Ok(Self::transpile_literal(lit)), |
17 | 253 | ExprKind::Identifier(name) => Ok(Self::transpile_identifier(name)), |
18 | 0 | ExprKind::QualifiedName { module, name } => { |
19 | 0 | Ok(Self::transpile_qualified_name(module, name)) |
20 | | } |
21 | 5 | ExprKind::StringInterpolation { parts } => self.transpile_string_interpolation(parts), |
22 | 0 | _ => unreachable!("Non-basic expression in transpile_basic_expr"), |
23 | | } |
24 | 682 | } |
25 | | |
26 | 253 | fn transpile_identifier(name: &str) -> TokenStream { |
27 | | // Handle Rust reserved keywords by prefixing with r# |
28 | | // Note: 'self', 'Self', 'super', and 'crate' cannot be raw identifiers |
29 | 253 | let safe_name = if matches!0 (name, "self" | "Self" | "super" | "crate") { |
30 | | // These keywords cannot be raw identifiers, use them as-is |
31 | 0 | name.to_string() |
32 | 253 | } else if Self::is_rust_reserved_keyword(name) { |
33 | 1 | format!("r#{name}") |
34 | | } else { |
35 | 252 | name.to_string() |
36 | | }; |
37 | | |
38 | 253 | let ident = format_ident!("{}", safe_name); |
39 | 253 | quote! { #ident } |
40 | 253 | } |
41 | | |
42 | 0 | fn transpile_qualified_name(module: &str, name: &str) -> TokenStream { |
43 | | // Handle nested qualified names like "net::TcpListener" |
44 | 0 | let module_parts: Vec<&str> = module.split("::").collect(); |
45 | 0 | let name_ident = format_ident!("{}", name); |
46 | | |
47 | 0 | if module_parts.len() == 1 { |
48 | | // Simple case: single module name |
49 | 0 | let module_ident = format_ident!("{}", module_parts[0]); |
50 | 0 | quote! { #module_ident::#name_ident } |
51 | | } else { |
52 | | // Complex case: nested path like "net::TcpListener" |
53 | 0 | let mut tokens = TokenStream::new(); |
54 | 0 | for (i, part) in module_parts.iter().enumerate() { |
55 | 0 | if i > 0 { |
56 | 0 | tokens.extend(quote! { :: }); |
57 | 0 | } |
58 | 0 | let part_ident = format_ident!("{}", part); |
59 | 0 | tokens.extend(quote! { #part_ident }); |
60 | | } |
61 | 0 | quote! { #tokens::#name_ident } |
62 | | } |
63 | 0 | } |
64 | | |
65 | | /// Transpile operator and control flow expressions (split for complexity) |
66 | 260 | pub(super) fn transpile_operator_control_expr(&self, expr: &Expr) -> Result<TokenStream> { |
67 | 260 | match &expr.kind { |
68 | | // Operators |
69 | | ExprKind::Binary { .. } |
70 | | | ExprKind::Unary { .. } |
71 | | | ExprKind::Assign { .. } |
72 | | | ExprKind::CompoundAssign { .. } |
73 | | | ExprKind::Await { .. } |
74 | 202 | | ExprKind::AsyncBlock { .. } => self.transpile_operator_only_expr(expr), |
75 | | // Control flow |
76 | | ExprKind::If { .. } |
77 | | | ExprKind::IfLet { .. } |
78 | | | ExprKind::WhileLet { .. } |
79 | | | ExprKind::Match { .. } |
80 | | | ExprKind::For { .. } |
81 | | | ExprKind::While { .. } |
82 | 58 | | ExprKind::Loop { .. } => self.transpile_control_flow_only_expr(expr), |
83 | 0 | _ => unreachable!("Non-operator/control expression in transpile_operator_control_expr"), |
84 | | } |
85 | 260 | } |
86 | | |
87 | 202 | fn transpile_operator_only_expr(&self, expr: &Expr) -> Result<TokenStream> { |
88 | 202 | match &expr.kind { |
89 | 151 | ExprKind::Binary { left, op, right } => self.transpile_binary(left, *op, right), |
90 | 50 | ExprKind::Unary { op, operand } => self.transpile_unary(*op, operand), |
91 | 0 | ExprKind::Assign { target, value } => self.transpile_assign(target, value), |
92 | 0 | ExprKind::CompoundAssign { target, op, value } => self.transpile_compound_assign(target, *op, value), |
93 | 1 | ExprKind::Await { expr } => self.transpile_await(expr), |
94 | 0 | ExprKind::AsyncBlock { body } => self.transpile_async_block(body), |
95 | 0 | _ => unreachable!(), |
96 | | } |
97 | 202 | } |
98 | | |
99 | 58 | fn transpile_control_flow_only_expr(&self, expr: &Expr) -> Result<TokenStream> { |
100 | 58 | match &expr.kind { |
101 | | ExprKind::If { |
102 | 48 | condition, |
103 | 48 | then_branch, |
104 | 48 | else_branch, |
105 | 48 | } => self.transpile_if(condition, then_branch, else_branch.as_deref()), |
106 | 6 | ExprKind::Match { expr, arms } => self.transpile_match(expr, arms), |
107 | 2 | ExprKind::For { var, pattern, iter, body } => self.transpile_for(var, pattern.as_ref(), iter, body), |
108 | 2 | ExprKind::While { condition, body } => self.transpile_while(condition, body), |
109 | | ExprKind::IfLet { |
110 | 0 | pattern, |
111 | 0 | expr, |
112 | 0 | then_branch, |
113 | 0 | else_branch, |
114 | 0 | } => self.transpile_if_let(pattern, expr, then_branch, else_branch.as_deref()), |
115 | | ExprKind::WhileLet { |
116 | 0 | pattern, |
117 | 0 | expr, |
118 | 0 | body, |
119 | 0 | } => self.transpile_while_let(pattern, expr, body), |
120 | 0 | ExprKind::Loop { body } => self.transpile_loop(body), |
121 | 0 | _ => unreachable!(), |
122 | | } |
123 | 58 | } |
124 | | |
125 | | /// Transpile function-related expressions |
126 | 83 | pub(super) fn transpile_function_expr(&self, expr: &Expr) -> Result<TokenStream> { |
127 | 83 | match &expr.kind { |
128 | | ExprKind::Function { |
129 | 18 | name, |
130 | 18 | type_params, |
131 | 18 | params, |
132 | 18 | body, |
133 | 18 | is_async, |
134 | 18 | return_type, |
135 | 18 | is_pub, |
136 | 18 | } => self.transpile_function( |
137 | 18 | name, |
138 | 18 | type_params, |
139 | 18 | params, |
140 | 18 | body, |
141 | 18 | *is_async, |
142 | 18 | return_type.as_ref(), |
143 | 18 | *is_pub, |
144 | 18 | &expr.attributes, |
145 | | ), |
146 | 11 | ExprKind::Lambda { params, body } => self.transpile_lambda(params, body), |
147 | 34 | ExprKind::Call { func, args } => self.transpile_call(func, args), |
148 | | ExprKind::MethodCall { |
149 | 20 | receiver, |
150 | 20 | method, |
151 | 20 | args, |
152 | 20 | } => self.transpile_method_call(receiver, method, args), |
153 | 0 | ExprKind::Macro { name, args } => self.transpile_macro(name, args), |
154 | 0 | _ => unreachable!("Non-function expression in transpile_function_expr"), |
155 | | } |
156 | 83 | } |
157 | | |
158 | | /// Transpile macro expressions with clean dispatch pattern |
159 | | /// |
160 | | /// This function uses specialized handlers for different macro categories: |
161 | | /// - Print macros: `println!`, `print!`, `panic!` (string formatting) |
162 | | /// - Collection macros: `vec!` (simple element transpilation) |
163 | | /// - Assertion macros: `assert!`, `assert_eq!`, `assert_ne!` (validation + transpilation) |
164 | | /// |
165 | | /// # Example Usage |
166 | | /// This method dispatches to specific macro handlers based on the macro name. |
167 | | /// For example, `println` calls `transpile_println_macro`, `vec` calls `transpile_vec_macro`, etc. |
168 | 0 | pub(super) fn transpile_macro(&self, name: &str, args: &[Expr]) -> Result<TokenStream> { |
169 | 0 | match name { |
170 | | // Print macros (string formatting) |
171 | 0 | "println" => self.transpile_println_macro(args), |
172 | 0 | "print" => self.transpile_print_macro(args), |
173 | 0 | "panic" => self.transpile_panic_macro(args), |
174 | | |
175 | | // Collection macros (simple transpilation) |
176 | 0 | "vec" => self.transpile_vec_macro(args), |
177 | | |
178 | | // Assertion macros (validation + transpilation) |
179 | 0 | "assert" => self.transpile_assert_macro(args), |
180 | 0 | "assert_eq" => self.transpile_assert_eq_macro(args), |
181 | 0 | "assert_ne" => self.transpile_assert_ne_macro(args), |
182 | | |
183 | 0 | _ => bail!("Unknown macro: {}", name), |
184 | | } |
185 | 0 | } |
186 | | |
187 | | /// Transpile structure-related expressions |
188 | 15 | pub(super) fn transpile_struct_expr(&self, expr: &Expr) -> Result<TokenStream> { |
189 | 15 | match &expr.kind { |
190 | | ExprKind::Struct { |
191 | 5 | name, |
192 | 5 | type_params, |
193 | 5 | fields, |
194 | 5 | is_pub, |
195 | 5 | } => self.transpile_struct(name, type_params, fields, *is_pub), |
196 | 1 | ExprKind::StructLiteral { name, fields } => self.transpile_struct_literal(name, fields), |
197 | 4 | ExprKind::ObjectLiteral { fields } => self.transpile_object_literal(fields), |
198 | 2 | ExprKind::FieldAccess { object, field } => self.transpile_field_access(object, field), |
199 | 1 | ExprKind::IndexAccess { object, index } => self.transpile_index_access(object, index), |
200 | 2 | ExprKind::Slice { object, start, end } => self.transpile_slice(object, start.as_deref(), end.as_deref()), |
201 | 0 | _ => unreachable!("Non-struct expression in transpile_struct_expr"), |
202 | | } |
203 | 15 | } |
204 | | |
205 | | /// Transpile data and error handling expressions (split for complexity) |
206 | 40 | pub(super) fn transpile_data_error_expr(&self, expr: &Expr) -> Result<TokenStream> { |
207 | 40 | match &expr.kind { |
208 | | ExprKind::DataFrame { .. } |
209 | | | ExprKind::DataFrameOperation { .. } |
210 | | | ExprKind::List(_) |
211 | | | ExprKind::Tuple(_) |
212 | | | ExprKind::ListComprehension { .. } |
213 | 40 | | ExprKind::Range { .. } => self.transpile_data_only_expr(expr), |
214 | | ExprKind::Throw { .. } |
215 | | | ExprKind::Ok { .. } |
216 | | | ExprKind::Err { .. } |
217 | | | ExprKind::Some { .. } |
218 | | | ExprKind::None |
219 | 0 | | ExprKind::Try { .. } => self.transpile_error_only_expr(expr), |
220 | 0 | _ => unreachable!("Non-data/error expression in transpile_data_error_expr"), |
221 | | } |
222 | 40 | } |
223 | | |
224 | 40 | fn transpile_data_only_expr(&self, expr: &Expr) -> Result<TokenStream> { |
225 | 40 | match &expr.kind { |
226 | 0 | ExprKind::DataFrame { columns } => self.transpile_dataframe(columns), |
227 | 0 | ExprKind::DataFrameOperation { source, operation } => { |
228 | 0 | self.transpile_dataframe_operation(source, operation) |
229 | | } |
230 | 32 | ExprKind::List(elements) => self.transpile_list(elements), |
231 | 1 | ExprKind::Tuple(elements) => self.transpile_tuple(elements), |
232 | | ExprKind::ListComprehension { |
233 | 3 | element, |
234 | 3 | variable, |
235 | 3 | iterable, |
236 | 3 | condition, |
237 | | } => { |
238 | 3 | self.transpile_list_comprehension(element, variable, iterable, condition.as_deref()) |
239 | | } |
240 | | ExprKind::Range { |
241 | 4 | start, |
242 | 4 | end, |
243 | 4 | inclusive, |
244 | 4 | } => self.transpile_range(start, end, *inclusive), |
245 | 0 | _ => unreachable!(), |
246 | | } |
247 | 40 | } |
248 | | |
249 | 0 | fn transpile_error_only_expr(&self, expr: &Expr) -> Result<TokenStream> { |
250 | 0 | match &expr.kind { |
251 | 0 | ExprKind::Throw { expr } => self.transpile_throw(expr), |
252 | 0 | ExprKind::Ok { value } => self.transpile_result_ok(value), |
253 | 0 | ExprKind::Err { error } => self.transpile_result_err(error), |
254 | 0 | ExprKind::Some { value } => self.transpile_option_some(value), |
255 | 0 | ExprKind::None => Ok(quote! { None }), |
256 | 0 | ExprKind::Try { expr } => self.transpile_try_operator(expr), |
257 | 0 | _ => unreachable!(), |
258 | | } |
259 | 0 | } |
260 | | |
261 | 0 | fn transpile_result_ok(&self, value: &Expr) -> Result<TokenStream> { |
262 | 0 | let value_tokens = self.transpile_expr(value)?; |
263 | 0 | Ok(quote! { Ok(#value_tokens) }) |
264 | 0 | } |
265 | | |
266 | 0 | fn transpile_result_err(&self, error: &Expr) -> Result<TokenStream> { |
267 | 0 | let error_tokens = self.transpile_expr(error)?; |
268 | 0 | Ok(quote! { Err(#error_tokens) }) |
269 | 0 | } |
270 | | |
271 | 0 | fn transpile_option_some(&self, value: &Expr) -> Result<TokenStream> { |
272 | 0 | let value_tokens = self.transpile_expr(value)?; |
273 | 0 | Ok(quote! { Some(#value_tokens) }) |
274 | 0 | } |
275 | | |
276 | 0 | fn transpile_try_operator(&self, expr: &Expr) -> Result<TokenStream> { |
277 | 0 | let expr_tokens = self.transpile_expr(expr)?; |
278 | 0 | Ok(quote! { #expr_tokens? }) |
279 | 0 | } |
280 | | |
281 | | /// Transpile actor system expressions |
282 | 3 | pub(super) fn transpile_actor_expr(&self, expr: &Expr) -> Result<TokenStream> { |
283 | 3 | match &expr.kind { |
284 | | ExprKind::Actor { |
285 | 1 | name, |
286 | 1 | state, |
287 | 1 | handlers, |
288 | 1 | } => self.transpile_actor(name, state, handlers), |
289 | 1 | ExprKind::Send { actor0 , message0 } | ExprKind::ActorSend { actor, message } => { |
290 | 1 | self.transpile_send(actor, message) |
291 | | } |
292 | | ExprKind::Ask { |
293 | 0 | actor, |
294 | 0 | message, |
295 | 0 | timeout, |
296 | 0 | } => self.transpile_ask(actor, message, timeout.as_deref()), |
297 | 1 | ExprKind::ActorQuery { actor, message } => { |
298 | | // Actor query is like Ask without timeout |
299 | 1 | self.transpile_ask(actor, message, None) |
300 | | } |
301 | 0 | ExprKind::Command { program, args, env, working_dir } => { |
302 | 0 | self.transpile_command(program, args, env, working_dir) |
303 | | } |
304 | 0 | _ => unreachable!("Non-actor expression in transpile_actor_expr"), |
305 | | } |
306 | 3 | } |
307 | | |
308 | | /// Transpile miscellaneous expressions |
309 | 46 | pub(super) fn transpile_misc_expr(&self, expr: &Expr) -> Result<TokenStream> { |
310 | 46 | match &expr.kind { |
311 | | ExprKind::Let { |
312 | 15 | name, |
313 | | type_annotation: _, |
314 | 15 | value, |
315 | 15 | body, |
316 | 15 | is_mutable, |
317 | 15 | } => self.transpile_let(name, value, body, *is_mutable), |
318 | | ExprKind::LetPattern { |
319 | 0 | pattern, |
320 | | type_annotation: _, |
321 | 0 | value, |
322 | 0 | body, |
323 | | is_mutable: _, |
324 | 0 | } => self.transpile_let_pattern(pattern, value, body), |
325 | 26 | ExprKind::Block(exprs) => self.transpile_block(exprs), |
326 | 1 | ExprKind::Pipeline { expr, stages } => self.transpile_pipeline(expr, stages), |
327 | 1 | ExprKind::Import { path, items } => Ok(Self::transpile_import(path, items)), |
328 | 0 | ExprKind::Module { name, body } => self.transpile_module(name, body), |
329 | | ExprKind::Trait { .. } |
330 | | | ExprKind::Impl { .. } |
331 | | | ExprKind::Extension { .. } |
332 | 3 | | ExprKind::Enum { .. } => self.transpile_type_decl_expr(expr), |
333 | | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } | ExprKind::Export { .. } => { |
334 | 0 | Self::transpile_control_misc_expr(expr) |
335 | | } |
336 | 0 | _ => bail!("Unsupported expression kind: {:?}", expr.kind), |
337 | | } |
338 | 46 | } |
339 | | |
340 | 3 | fn transpile_type_decl_expr(&self, expr: &Expr) -> Result<TokenStream> { |
341 | 3 | match &expr.kind { |
342 | | ExprKind::Trait { |
343 | 1 | name, |
344 | 1 | type_params, |
345 | 1 | methods, |
346 | 1 | is_pub, |
347 | 1 | } => self.transpile_trait(name, type_params, methods, *is_pub), |
348 | | ExprKind::Impl { |
349 | 1 | type_params, |
350 | 1 | trait_name, |
351 | 1 | for_type, |
352 | 1 | methods, |
353 | 1 | is_pub, |
354 | 1 | } => self.transpile_impl(for_type, type_params, trait_name.as_deref(), methods, *is_pub), |
355 | | ExprKind::Extension { |
356 | 0 | target_type, |
357 | 0 | methods, |
358 | 0 | } => self.transpile_extend(target_type, methods), |
359 | | ExprKind::Enum { |
360 | 1 | name, |
361 | 1 | type_params, |
362 | 1 | variants, |
363 | 1 | is_pub, |
364 | 1 | } => self.transpile_enum(name, type_params, variants, *is_pub), |
365 | 0 | _ => unreachable!(), |
366 | | } |
367 | 3 | } |
368 | | |
369 | | /// Transpile println! macro with string formatting support |
370 | | /// |
371 | | /// Handles string literals, string interpolation, and format strings correctly. |
372 | | /// Complexity: <10 per Toyota Way requirement. |
373 | | /// |
374 | | /// # Example Usage |
375 | | /// Transpiles arguments and wraps them in Rust's `println!` macro. |
376 | | /// Empty args produce `println!()`, otherwise `println!(arg1, arg2, ...)` |
377 | 0 | fn transpile_println_macro(&self, args: &[Expr]) -> Result<TokenStream> { |
378 | 0 | let arg_tokens = self.transpile_print_args(args)?; |
379 | 0 | if arg_tokens.is_empty() { |
380 | 0 | Ok(quote! { println!() }) |
381 | | } else { |
382 | 0 | Ok(quote! { println!(#(#arg_tokens),*) }) |
383 | | } |
384 | 0 | } |
385 | | |
386 | | /// Transpile print! macro with string formatting support |
387 | | /// |
388 | | /// Handles string literals, string interpolation, and format strings correctly. |
389 | | /// Complexity: <10 per Toyota Way requirement. |
390 | | /// |
391 | | /// # Example Usage |
392 | | /// Transpiles arguments and wraps them in Rust's `print!` macro. |
393 | | /// Empty args produce `print!()`, otherwise `print!(arg1, arg2, ...)` |
394 | 0 | fn transpile_print_macro(&self, args: &[Expr]) -> Result<TokenStream> { |
395 | 0 | let arg_tokens = self.transpile_print_args(args)?; |
396 | 0 | if arg_tokens.is_empty() { |
397 | 0 | Ok(quote! { print!() }) |
398 | | } else { |
399 | 0 | Ok(quote! { print!(#(#arg_tokens),*) }) |
400 | | } |
401 | 0 | } |
402 | | |
403 | | /// Transpile panic! macro with string formatting support |
404 | | /// |
405 | | /// Handles string literals, string interpolation, and format strings correctly. |
406 | | /// Complexity: <10 per Toyota Way requirement. |
407 | | /// |
408 | | /// # Example Usage |
409 | | /// Transpiles arguments and wraps them in Rust's `panic!` macro. |
410 | | /// Empty args produce `panic!()`, otherwise `panic!(arg1, arg2, ...)` |
411 | 0 | fn transpile_panic_macro(&self, args: &[Expr]) -> Result<TokenStream> { |
412 | 0 | let arg_tokens = self.transpile_print_args(args)?; |
413 | 0 | if arg_tokens.is_empty() { |
414 | 0 | Ok(quote! { panic!() }) |
415 | | } else { |
416 | 0 | Ok(quote! { panic!(#(#arg_tokens),*) }) |
417 | | } |
418 | 0 | } |
419 | | |
420 | | /// Common helper for transpiling print-style macro arguments |
421 | | /// |
422 | | /// Handles string literals, string interpolation, and format strings. |
423 | | /// This eliminates code duplication between println!, print!, and panic!. |
424 | | /// Complexity: <10 per Toyota Way requirement. |
425 | 0 | fn transpile_print_args(&self, args: &[Expr]) -> Result<Vec<TokenStream>> { |
426 | 0 | args.iter() |
427 | 0 | .map(|arg| { |
428 | 0 | match &arg.kind { |
429 | 0 | ExprKind::Literal(Literal::String(s)) => { |
430 | 0 | Ok(quote! { #s }) |
431 | | } |
432 | 0 | ExprKind::StringInterpolation { parts } => { |
433 | 0 | self.transpile_string_interpolation_for_print(parts) |
434 | | } |
435 | | _ => { |
436 | | // Use Debug formatting for all non-string expressions to be safe |
437 | | // This prevents Display trait errors and works with all types |
438 | 0 | let expr_tokens = self.transpile_expr(arg)?; |
439 | 0 | Ok(quote! { "{:?}", #expr_tokens }) |
440 | | } |
441 | | } |
442 | 0 | }) |
443 | 0 | .collect() |
444 | 0 | } |
445 | | |
446 | | |
447 | | /// Handle string interpolation for print-style macros |
448 | | /// |
449 | | /// Detects if string interpolation has expressions or is just format text. |
450 | | /// Complexity: <10 per Toyota Way requirement. |
451 | 0 | fn transpile_string_interpolation_for_print(&self, parts: &[crate::frontend::ast::StringPart]) -> Result<TokenStream> { |
452 | 0 | let has_expressions = parts.iter().any(|part| matches!(part, |
453 | | crate::frontend::ast::StringPart::Expr(_) | |
454 | | crate::frontend::ast::StringPart::ExprWithFormat { .. })); |
455 | | |
456 | 0 | if has_expressions { |
457 | | // This has actual interpolation - transpile normally |
458 | 0 | self.transpile_string_interpolation(parts) |
459 | | } else { |
460 | | // This is a format string like "Hello {}" - treat as literal |
461 | 0 | let format_string = parts.iter() |
462 | 0 | .map(|part| match part { |
463 | 0 | crate::frontend::ast::StringPart::Text(s) => s.as_str(), |
464 | | crate::frontend::ast::StringPart::Expr(_) | |
465 | 0 | crate::frontend::ast::StringPart::ExprWithFormat { .. } => unreachable!() |
466 | 0 | }) |
467 | 0 | .collect::<String>(); |
468 | 0 | Ok(quote! { #format_string }) |
469 | | } |
470 | 0 | } |
471 | | |
472 | | /// Transpile vec! macro |
473 | | /// |
474 | | /// Simple element-by-element transpilation for collection creation. |
475 | | /// Complexity: <10 per Toyota Way requirement. |
476 | | /// |
477 | | /// # Example Usage |
478 | | /// Transpiles list elements and wraps them in Rust's `vec!` macro. |
479 | | /// Produces `vec![elem1, elem2, ...]` |
480 | 0 | fn transpile_vec_macro(&self, args: &[Expr]) -> Result<TokenStream> { |
481 | 0 | let arg_tokens: Result<Vec<_>, _> = args |
482 | 0 | .iter() |
483 | 0 | .map(|arg| self.transpile_expr(arg)) |
484 | 0 | .collect(); |
485 | 0 | let arg_tokens = arg_tokens?; |
486 | | |
487 | 0 | Ok(quote! { vec![#(#arg_tokens),*] }) |
488 | 0 | } |
489 | | |
490 | | /// Transpile assert! macro |
491 | | /// |
492 | | /// Simple argument transpilation for basic assertions. |
493 | | /// Complexity: <10 per Toyota Way requirement. |
494 | | /// |
495 | | /// # Example Usage |
496 | | /// Transpiles assertion condition and wraps it in Rust's `assert!` macro. |
497 | | /// Produces `assert!(condition, optional_message)` |
498 | 0 | fn transpile_assert_macro(&self, args: &[Expr]) -> Result<TokenStream> { |
499 | 0 | let arg_tokens: Result<Vec<_>, _> = args |
500 | 0 | .iter() |
501 | 0 | .map(|arg| self.transpile_expr(arg)) |
502 | 0 | .collect(); |
503 | 0 | let arg_tokens = arg_tokens?; |
504 | | |
505 | 0 | if arg_tokens.is_empty() { |
506 | 0 | Ok(quote! { assert!() }) |
507 | | } else { |
508 | 0 | Ok(quote! { assert!(#(#arg_tokens),*) }) |
509 | | } |
510 | 0 | } |
511 | | |
512 | | /// Transpile `assert_eq`! macro with validation |
513 | | /// |
514 | | /// Validates argument count and transpiles for equality assertions. |
515 | | /// Complexity: <10 per Toyota Way requirement. |
516 | | /// |
517 | | /// # Example Usage |
518 | | /// Validates at least 2 arguments and transpiles to Rust's `assert_eq!` macro. |
519 | | /// Produces `assert_eq!(left, right, optional_message)` |
520 | 0 | fn transpile_assert_eq_macro(&self, args: &[Expr]) -> Result<TokenStream> { |
521 | 0 | if args.len() < 2 { |
522 | 0 | bail!("assert_eq! requires at least 2 arguments") |
523 | 0 | } |
524 | | |
525 | 0 | let arg_tokens: Result<Vec<_>, _> = args |
526 | 0 | .iter() |
527 | 0 | .map(|arg| self.transpile_expr(arg)) |
528 | 0 | .collect(); |
529 | 0 | let arg_tokens = arg_tokens?; |
530 | | |
531 | 0 | Ok(quote! { assert_eq!(#(#arg_tokens),*) }) |
532 | 0 | } |
533 | | |
534 | | /// Transpile `assert_ne`! macro with validation |
535 | | /// |
536 | | /// Validates argument count and transpiles for inequality assertions. |
537 | | /// Complexity: <10 per Toyota Way requirement. |
538 | | /// |
539 | | /// # Example Usage |
540 | | /// Validates at least 2 arguments and transpiles to Rust's `assert_ne!` macro. |
541 | | /// Produces `assert_ne!(left, right, optional_message)` |
542 | 0 | fn transpile_assert_ne_macro(&self, args: &[Expr]) -> Result<TokenStream> { |
543 | 0 | if args.len() < 2 { |
544 | 0 | bail!("assert_ne! requires at least 2 arguments") |
545 | 0 | } |
546 | | |
547 | 0 | let arg_tokens: Result<Vec<_>, _> = args |
548 | 0 | .iter() |
549 | 0 | .map(|arg| self.transpile_expr(arg)) |
550 | 0 | .collect(); |
551 | 0 | let arg_tokens = arg_tokens?; |
552 | | |
553 | 0 | Ok(quote! { assert_ne!(#(#arg_tokens),*) }) |
554 | 0 | } |
555 | | |
556 | 0 | fn transpile_control_misc_expr(expr: &Expr) -> Result<TokenStream> { |
557 | 0 | match &expr.kind { |
558 | 0 | ExprKind::Break { label } => Ok(Self::make_break_continue(true, label.as_ref())), |
559 | 0 | ExprKind::Continue { label } => Ok(Self::make_break_continue(false, label.as_ref())), |
560 | 0 | ExprKind::Return { value } => { |
561 | 0 | if let Some(val) = value { |
562 | 0 | let transpiler = Transpiler::new(); |
563 | 0 | let val_tokens = transpiler.transpile_expr(val)?; |
564 | 0 | Ok(quote! { return #val_tokens }) |
565 | | } else { |
566 | 0 | Ok(quote! { return }) |
567 | | } |
568 | | } |
569 | 0 | ExprKind::Export { items } => { |
570 | 0 | let item_idents: Vec<_> = |
571 | 0 | items.iter().map(|item| format_ident!("{}", item)).collect(); |
572 | 0 | Ok(quote! { pub use { #(#item_idents),* }; }) |
573 | | } |
574 | 0 | _ => unreachable!(), |
575 | | } |
576 | 0 | } |
577 | | |
578 | 0 | fn make_break_continue(is_break: bool, label: Option<&String>) -> TokenStream { |
579 | 0 | let keyword = if is_break { |
580 | 0 | quote! { break } |
581 | | } else { |
582 | 0 | quote! { continue } |
583 | | }; |
584 | 0 | match label { |
585 | 0 | Some(l) => { |
586 | 0 | let label_ident = format_ident!("{}", l); |
587 | 0 | quote! { #keyword #label_ident } |
588 | | } |
589 | 0 | None => keyword, |
590 | | } |
591 | 0 | } |
592 | | |
593 | | } |