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

    Line
    Count
    Source
    1
    //! Minimal codegen for self-hosting MVP
    2
    //! Direct Rust mapping with no optimization - as specified in self-hosting spec
    3
    4
    #![allow(clippy::missing_errors_doc)]
    5
    6
    use crate::frontend::ast::{Expr, ExprKind, Literal, Pattern, BinaryOp, UnaryOp};
    7
    use anyhow::Result;
    8
    9
    /// Minimal code generator for self-hosting
    10
    pub struct MinimalCodeGen;
    11
    12
    impl MinimalCodeGen {
    13
        /// Generate Rust code directly from AST with no optimization
    14
    0
        pub fn gen_expr(expr: &Expr) -> Result<String> {
    15
    0
            match &expr.kind {
    16
    0
                ExprKind::Literal(lit) => Self::gen_literal(lit),
    17
    18
    0
                ExprKind::Identifier(name) => Ok(name.clone()),
    19
    20
    0
                ExprKind::Binary { left, op, right } => {
    21
    0
                    let left_code = Self::gen_expr(left)?;
    22
    0
                    let right_code = Self::gen_expr(right)?;
    23
    0
                    let op_code = Self::gen_binary_op(*op);
    24
    0
                    Ok(format!("({left_code} {op_code} {right_code})"))
    25
                }
    26
    27
    0
                ExprKind::Unary { op, operand } => {
    28
    0
                    let operand_code = Self::gen_expr(operand)?;
    29
    0
                    let op_code = Self::gen_unary_op(*op);
    30
    0
                    Ok(format!("({op_code} {operand_code})"))
    31
                }
    32
    33
    0
                ExprKind::Let { name, value, body, .. } => {
    34
    0
                    let value_code = Self::gen_expr(value)?;
    35
    0
                    let body_code = Self::gen_expr(body)?;
    36
    0
                    Ok(format!("{{ let {name} = {value_code}; {body_code} }}"))
    37
                }
    38
    39
    0
                ExprKind::Function { name, params, body, .. } => {
    40
    0
                    let param_list = params.iter()
    41
    0
                        .map(|p| { let name = p.name(); format!("{name}: i32") }) // Simplified for MVP
    42
    0
                        .collect::<Vec<_>>()
    43
    0
                        .join(", ");
    44
    0
                    let body_code = Self::gen_expr(body)?;
    45
    0
                    Ok(format!("fn {name}({param_list}) {{ {body_code} }}"))
    46
                }
    47
    48
    0
                ExprKind::Lambda { params, body } => {
    49
    0
                    let param_list = params.iter()
    50
    0
                        .map(crate::frontend::ast::Param::name)
    51
    0
                        .collect::<Vec<_>>()
    52
    0
                        .join(", ");
    53
    0
                    let body_code = Self::gen_expr(body)?;
    54
    0
                    Ok(format!("|{param_list}| {body_code}"))
    55
                }
    56
    57
    0
                ExprKind::Call { func, args } => {
    58
    0
                    let func_code = Self::gen_expr(func)?;
    59
    0
                    let arg_codes = args.iter()
    60
    0
                        .map(Self::gen_expr)
    61
    0
                        .collect::<Result<Vec<_>>>()?;
    62
    0
                    Ok(format!("{func_code}({})", arg_codes.join(", ")))
    63
                }
    64
    65
    0
                ExprKind::If { condition, then_branch, else_branch } => {
    66
    0
                    let cond_code = Self::gen_expr(condition)?;
    67
    0
                    let then_code = Self::gen_expr(then_branch)?;
    68
    0
                    if let Some(else_expr) = else_branch {
    69
    0
                        let else_code = Self::gen_expr(else_expr)?;
    70
    0
                        Ok(format!("if {cond_code} {{ {then_code} }} else {{ {else_code} }}"))
    71
                    } else {
    72
    0
                        Ok(format!("if {cond_code} {{ {then_code} }}"))
    73
                    }
    74
                }
    75
    76
    0
                ExprKind::Block(exprs) => {
    77
    0
                    let mut code = String::new();
    78
    0
                    code.push_str("{ ");
    79
    0
                    for (i, expr) in exprs.iter().enumerate() {
    80
    0
                        let expr_code = Self::gen_expr(expr)?;
    81
    0
                        if i == exprs.len() - 1 {
    82
    0
                            // Last expression is the return value
    83
    0
                            code.push_str(&expr_code);
    84
    0
                        } else {
    85
    0
                            code.push_str(&format!("{expr_code}; "));
    86
    0
                        }
    87
                    }
    88
    0
                    code.push_str(" }");
    89
    0
                    Ok(code)
    90
                }
    91
    92
    0
                ExprKind::Match { expr, arms } => {
    93
    0
                    let expr_code = Self::gen_expr(expr)?;
    94
    0
                    let mut code = format!("match {expr_code} {{\n");
    95
    0
                    for arm in arms {
    96
    0
                        let pattern_code = Self::gen_pattern(&arm.pattern)?;
    97
    0
                        let body_code = Self::gen_expr(&arm.body)?;
    98
    0
                        code.push_str(&format!("    {pattern_code} => {body_code},\n"));
    99
                    }
    100
    0
                    code.push('}');
    101
    0
                    Ok(code)
    102
                }
    103
    104
    0
                ExprKind::List(elements) => {
    105
    0
                    let element_codes = elements.iter()
    106
    0
                        .map(Self::gen_expr)
    107
    0
                        .collect::<Result<Vec<_>>>()?;
    108
    0
                    let elements = element_codes.join(", ");
    109
    0
                    Ok(format!("vec![{elements}]"))
    110
                }
    111
    112
    0
                ExprKind::Struct { name, fields, .. } => {
    113
    0
                    let field_list = fields.iter()
    114
    0
                        .map(|f| { let name = &f.name; format!("    {name}: String,") }) // Simplified for MVP
    115
    0
                        .collect::<Vec<_>>()
    116
    0
                        .join("\n");
    117
    0
                    Ok(format!("struct {name} {{\n{field_list}\n}}"))
    118
                }
    119
    120
    0
                ExprKind::StructLiteral { name, fields } => {
    121
    0
                    let field_codes = fields.iter()
    122
    0
                        .map(|f| {
    123
    0
                            let value_code = Self::gen_expr(&f.1)?;
    124
    0
                            let field_name = &f.0;
    125
    0
                            Ok(format!("{field_name}: {value_code}"))
    126
    0
                        })
    127
    0
                        .collect::<Result<Vec<_>>>()?;
    128
    0
                    let fields = field_codes.join(", ");
    129
    0
                    Ok(format!("{name} {{ {fields} }}"))
    130
                }
    131
    132
    0
                ExprKind::MethodCall { receiver, method, args } => {
    133
    0
                    let receiver_code = Self::gen_expr(receiver)?;
    134
    0
                    let arg_codes = args.iter()
    135
    0
                        .map(Self::gen_expr)
    136
    0
                        .collect::<Result<Vec<_>>>()?;
    137
    0
                    let args = arg_codes.join(", ");
    138
    0
                    Ok(format!("{receiver_code}.{method}({args})"))
    139
                }
    140
    141
    0
                ExprKind::Macro { name, args } => {
    142
    0
                    let arg_codes = args.iter()
    143
    0
                        .map(Self::gen_expr)
    144
    0
                        .collect::<Result<Vec<_>>>()?;
    145
    0
                    let args = arg_codes.join(", ");
    146
    0
                    Ok(format!("{name}!({args})"))
    147
                }
    148
    149
    0
                ExprKind::QualifiedName { module, name } => {
    150
    0
                    Ok(format!("{module}::{name}"))
    151
                }
    152
    153
    0
                ExprKind::StringInterpolation { parts } => {
    154
                    // Simplified string interpolation for MVP
    155
    0
                    let mut result = String::from("format!(");
    156
    0
                    let mut format_str = String::new();
    157
    0
                    let mut args = Vec::new();
    158
    159
    0
                    for part in parts {
    160
    0
                        match part {
    161
    0
                            crate::frontend::ast::StringPart::Text(s) => {
    162
    0
                                format_str.push_str(s);
    163
    0
                            }
    164
    0
                            crate::frontend::ast::StringPart::Expr(expr) => {
    165
    0
                                format_str.push_str("{}");
    166
    0
                                args.push(Self::gen_expr(expr)?);
    167
                            }
    168
    0
                            crate::frontend::ast::StringPart::ExprWithFormat { expr, format_spec } => {
    169
    0
                                format_str.push('{');
    170
    0
                                format_str.push_str(format_spec);
    171
    0
                                format_str.push('}');
    172
    0
                                args.push(Self::gen_expr(expr)?);
    173
                            }
    174
                        }
    175
                    }
    176
    177
    0
                    result.push_str(&format!("\"{format_str}\""));
    178
    0
                    if !args.is_empty() {
    179
    0
                        result.push_str(", ");
    180
    0
                        result.push_str(&args.join(", "));
    181
    0
                    }
    182
    0
                    result.push(')');
    183
    0
                    Ok(result)
    184
                }
    185
    186
                _ => {
    187
                    // For self-hosting MVP, unsupported constructs generate compile errors
    188
                    // This ensures developers know what needs to be implemented
    189
    0
                    Err(anyhow::anyhow!(
    190
    0
                        "Minimal codegen does not support {:?} - use full transpiler for complete language support",
    191
    0
                        expr.kind
    192
    0
                    ))
    193
                }
    194
            }
    195
    0
        }
    196
    197
    0
        fn gen_literal(lit: &Literal) -> Result<String> {
    198
    0
            match lit {
    199
    0
                Literal::Integer(i) => Ok(i.to_string()),
    200
    0
                Literal::Float(f) => Ok(f.to_string()),
    201
    0
                Literal::String(s) => Ok(format!("\"{}\"", s.replace('"', "\\\""))),
    202
    0
                Literal::Bool(b) => Ok(b.to_string()),
    203
    0
                Literal::Char(c) => Ok(format!("'{c}'")),
    204
    0
                Literal::Unit => Ok("()".to_string()),
    205
            }
    206
    0
        }
    207
    208
    0
        fn gen_binary_op(op: BinaryOp) -> &'static str {
    209
    0
            match op {
    210
    0
                BinaryOp::Add => "+",
    211
    0
                BinaryOp::Subtract => "-",
    212
    0
                BinaryOp::Multiply => "*",
    213
    0
                BinaryOp::Divide => "/",
    214
    0
                BinaryOp::Modulo => "%",
    215
    0
                BinaryOp::Equal => "==",
    216
    0
                BinaryOp::NotEqual => "!=",
    217
    0
                BinaryOp::Less => "<",
    218
    0
                BinaryOp::LessEqual => "<=",
    219
    0
                BinaryOp::Greater => ">",
    220
    0
                BinaryOp::GreaterEqual => ">=",
    221
    0
                BinaryOp::And => "&&",
    222
    0
                BinaryOp::Or => "||",
    223
    0
                BinaryOp::NullCoalesce => "??", // JavaScript-style null coalescing
    224
    0
                BinaryOp::BitwiseAnd => "&",
    225
    0
                BinaryOp::BitwiseOr => "|",
    226
    0
                BinaryOp::BitwiseXor => "^",
    227
    0
                BinaryOp::LeftShift => "<<",
    228
    0
                BinaryOp::Power => "pow", // Will need function call wrapper
    229
            }
    230
    0
        }
    231
    232
    0
        fn gen_unary_op(op: UnaryOp) -> &'static str {
    233
    0
            match op {
    234
    0
                UnaryOp::Not => "!",
    235
    0
                UnaryOp::Negate => "-",
    236
    0
                UnaryOp::BitwiseNot => "~",
    237
    0
                UnaryOp::Reference => "&",
    238
            }
    239
    0
        }
    240
    241
    0
        fn gen_pattern(pattern: &Pattern) -> Result<String> {
    242
    0
            match pattern {
    243
    0
                Pattern::Wildcard => Ok("_".to_string()),
    244
    0
                Pattern::Literal(lit) => Self::gen_literal(lit),
    245
    0
                Pattern::Identifier(name) => Ok(name.clone()),
    246
    0
                Pattern::List(patterns) => {
    247
    0
                    let pattern_codes = patterns.iter()
    248
    0
                        .map(Self::gen_pattern)
    249
    0
                        .collect::<Result<Vec<_>>>()?;
    250
    0
                    let patterns = pattern_codes.join(", ");
    251
    0
                    Ok(format!("[{patterns}]"))
    252
                }
    253
    0
                Pattern::Ok(inner) => {
    254
    0
                    let inner_code = Self::gen_pattern(inner)?;
    255
    0
                    Ok(format!("Ok({inner_code})"))
    256
                }
    257
    0
                Pattern::Err(inner) => {
    258
    0
                    let inner_code = Self::gen_pattern(inner)?;
    259
    0
                    Ok(format!("Err({inner_code})"))
    260
                }
    261
    0
                Pattern::Some(inner) => {
    262
    0
                    let inner_code = Self::gen_pattern(inner)?;
    263
    0
                    Ok(format!("Some({inner_code})"))
    264
                }
    265
    0
                Pattern::None => Ok("None".to_string()),
    266
    0
                _ => Ok("_".to_string()), // Simplified for MVP
    267
            }
    268
    0
        }
    269
    270
        // Type generation simplified for MVP - focus on minimal working compiler
    271
        #[allow(dead_code)]
    272
    0
        fn gen_type(_ty: &crate::frontend::ast::Type) -> Result<String> {
    273
    0
            Ok("String".to_string()) // Simplified for self-hosting MVP
    274
    0
        }
    275
    276
        /// Generate complete Rust program for self-hosting
    277
    0
        pub fn gen_program(expr: &Expr) -> Result<String> {
    278
    0
            let main_code = Self::gen_expr(expr)?;
    279
    0
            Ok(format!(
    280
    0
                "use std::collections::HashMap;\n\n{main_code}"
    281
    0
            ))
    282
    0
        }
    283
    }
    284
    285
    #[cfg(test)]
    286
    mod tests {
    287
        use super::*;
    288
        use crate::frontend::parser::Parser;
    289
    290
        fn gen_str(input: &str) -> Result<String> {
    291
            let mut parser = Parser::new(input);
    292
            let expr = parser.parse()?;
    293
            MinimalCodeGen::gen_expr(&expr)
    294
        }
    295
    296
        #[test]
    297
        fn test_basic_expressions() {
    298
            assert_eq!(gen_str("42").unwrap(), "42");
    299
            assert_eq!(gen_str("true").unwrap(), "true");
    300
            assert_eq!(gen_str("\"hello\"").unwrap(), "\"hello\"");
    301
        }
    302
    303
        #[test]
    304
        fn test_binary_ops() {
    305
            assert_eq!(gen_str("1 + 2").unwrap(), "(1 + 2)");
    306
            assert_eq!(gen_str("x * y").unwrap(), "(x * y)");
    307
        }
    308
    309
        #[test]
    310
        fn test_function_def() {
    311
            let result = gen_str("fun add(x: i32, y: i32) -> i32 { x + y }").unwrap();
    312
            assert!(result.contains("fn add(x: i32, y: i32)"));
    313
        }
    314
    315
        #[test]
    316
        fn test_lambda() {
    317
            assert_eq!(gen_str("|x| x + 1").unwrap(), "|x| (x + 1)");
    318
        }
    319
    320
        #[test]
    321
        fn test_list() {
    322
            assert_eq!(gen_str("[1, 2, 3]").unwrap(), "vec![1, 2, 3]");
    323
        }
    324
    }