## 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/actors.rs

    Line
    Count
    Source
    1
    //! Actor system transpilation
    2
    3
    #![allow(clippy::missing_errors_doc)]
    4
    #![allow(clippy::wildcard_imports)]
    5
    6
    use super::*;
    7
    use crate::frontend::ast::{ActorHandler, StructField};
    8
    use anyhow::Result;
    9
    use proc_macro2::TokenStream;
    10
    use quote::{format_ident, quote};
    11
    12
    impl Transpiler {
    13
        /// Transpiles actor definitions
    14
    0
        pub fn transpile_actor(
    15
    0
            &self,
    16
    0
            name: &str,
    17
    0
            state: &[StructField],
    18
    0
            handlers: &[ActorHandler],
    19
    0
        ) -> Result<TokenStream> {
    20
    0
            let actor_name = format_ident!("{}", name);
    21
    0
            let message_enum_name = format_ident!("{}Message", name);
    22
    23
            // Generate state fields
    24
    0
            let state_fields: Vec<TokenStream> = state
    25
    0
                .iter()
    26
    0
                .map(|field| {
    27
    0
                    let field_name = format_ident!("{}", field.name);
    28
    0
                    let field_type = self
    29
    0
                        .transpile_type(&field.ty)
    30
    0
                        .unwrap_or_else(|_| quote! { _ });
    31
    0
                    quote! { #field_name: #field_type }
    32
    0
                })
    33
    0
                .collect();
    34
    35
            // Generate message enum variants
    36
    0
            let mut message_variants = Vec::new();
    37
    0
            let mut handler_arms = Vec::new();
    38
    39
    0
            for handler in handlers {
    40
    0
                let variant_name = format_ident!("{}", handler.message_type);
    41
    42
    0
                if handler.params.is_empty() {
    43
                    // Simple message without parameters
    44
    0
                    message_variants.push(quote! { #variant_name });
    45
    46
    0
                    let body_tokens = self.transpile_expr(&handler.body)?;
    47
    0
                    handler_arms.push(quote! {
    48
                        #message_enum_name::#variant_name => {
    49
                            #body_tokens
    50
                        }
    51
                    });
    52
                } else {
    53
                    // Message with parameters
    54
    0
                    let param_types: Vec<TokenStream> = handler
    55
    0
                        .params
    56
    0
                        .iter()
    57
    0
                        .map(|p| {
    58
    0
                            self.transpile_type(&p.ty)
    59
    0
                                .unwrap_or_else(|_| quote! { String })
    60
    0
                        })
    61
    0
                        .collect();
    62
    63
    0
                    if param_types.len() == 1 {
    64
    0
                        message_variants.push(quote! { #variant_name(#(#param_types),*) });
    65
                    } else {
    66
    0
                        message_variants.push(quote! { #variant_name { #(#param_types),* } });
    67
                    }
    68
    69
                    // Generate parameter bindings for the handler
    70
    0
                    let param_names: Vec<_> = handler
    71
    0
                        .params
    72
    0
                        .iter()
    73
    0
                        .map(|p| format_ident!("{}", p.name()))
    74
    0
                        .collect();
    75
    76
    0
                    let body_tokens = self.transpile_expr(&handler.body)?;
    77
    78
    0
                    if param_names.len() == 1 {
    79
    0
                        let param = &param_names[0];
    80
    0
                        handler_arms.push(quote! {
    81
    0
                            #message_enum_name::#variant_name(#param) => {
    82
    0
                                #body_tokens
    83
    0
                            }
    84
    0
                        });
    85
    0
                    } else {
    86
    0
                        handler_arms.push(quote! {
    87
                            #message_enum_name::#variant_name { #(#param_names),* } => {
    88
                                #body_tokens
    89
                            }
    90
                        });
    91
                    }
    92
                }
    93
            }
    94
    95
            // Generate the complete actor implementation
    96
    0
            Ok(quote! {
    97
                // Message enum
    98
                #[derive(Debug, Clone)]
    99
                enum #message_enum_name {
    100
                    #(#message_variants,)*
    101
                }
    102
    103
                // Actor struct
    104
                struct #actor_name {
    105
                    #(#state_fields,)*
    106
                    receiver: tokio::sync::mpsc::Receiver<#message_enum_name>,
    107
                    sender: tokio::sync::mpsc::Sender<#message_enum_name>,
    108
                }
    109
    110
                impl #actor_name {
    111
                    fn new() -> Self {
    112
                        let (sender, receiver) = tokio::sync::mpsc::channel(100);
    113
                        Self {
    114
                            #(#state_fields: Default::default(),)*
    115
                            receiver,
    116
                            sender,
    117
                        }
    118
                    }
    119
    120
                    fn sender(&self) -> tokio::sync::mpsc::Sender<#message_enum_name> {
    121
                        self.sender.clone()
    122
                    }
    123
    124
                    async fn run(&mut self) {
    125
                        while let Some(msg) = self.receiver.recv().await {
    126
                            self.handle_message(msg).await;
    127
                        }
    128
                    }
    129
    130
                    async fn handle_message(&mut self, msg: #message_enum_name) {
    131
                        match msg {
    132
                            #(#handler_arms)*
    133
                        }
    134
                    }
    135
                }
    136
            })
    137
    0
        }
    138
    139
        /// Transpiles send operations (actor ! message)
    140
    0
        pub fn transpile_send(&self, actor: &Expr, message: &Expr) -> Result<TokenStream> {
    141
    0
            let actor_tokens = self.transpile_expr(actor)?;
    142
    0
            let message_tokens = self.transpile_expr(message)?;
    143
    144
    0
            Ok(quote! {
    145
    0
                #actor_tokens.send(#message_tokens).await
    146
    0
            })
    147
    0
        }
    148
    149
        /// Transpiles ask operations (actor ? message)
    150
    0
        pub fn transpile_ask(
    151
    0
            &self,
    152
    0
            actor: &Expr,
    153
    0
            message: &Expr,
    154
    0
            timeout: Option<&Expr>,
    155
    0
        ) -> Result<TokenStream> {
    156
    0
            let actor_tokens = self.transpile_expr(actor)?;
    157
    0
            let message_tokens = self.transpile_expr(message)?;
    158
    159
    0
            if let Some(timeout_expr) = timeout {
    160
    0
                let timeout_tokens = self.transpile_expr(timeout_expr)?;
    161
    0
                Ok(quote! {
    162
    0
                    #actor_tokens.ask(#message_tokens, #timeout_tokens).await
    163
    0
                })
    164
            } else {
    165
                // Default timeout of 5 seconds
    166
    0
                Ok(quote! {
    167
    0
                    #actor_tokens.ask(#message_tokens, std::time::Duration::from_secs(5)).await
    168
    0
                })
    169
            }
    170
    0
        }
    171
    172
        /// Transpiles command execution
    173
    0
        pub fn transpile_command(
    174
    0
            &self,
    175
    0
            program: &str,
    176
    0
            args: &[String],
    177
    0
            _env: &[(String, String)],
    178
    0
            _working_dir: &Option<String>,
    179
    0
        ) -> Result<TokenStream> {
    180
    0
            let prog_str = program;
    181
    0
            let args_tokens: Vec<_> = args.iter().map(|arg| quote! { #arg }).collect();
    182
    183
    0
            Ok(quote! {
    184
                std::process::Command::new(#prog_str)
    185
                    .args(&[#(#args_tokens),*])
    186
                    .output()
    187
                    .expect("Failed to execute command")
    188
            })
    189
    0
        }
    190
    }