Skip to main content

palladium/codegen/
llvm_text_backend.rs

1// Text-based LLVM IR backend for Palladium
2// "Native code generation without dependencies"
3
4use crate::ast::{ArraySize, AssignTarget, BinOp, Expr, Function, Item, Pattern, Program, Stmt, Type, UnaryOp};
5use crate::errors::{CompileError, Result};
6use std::collections::HashMap;
7use std::path::PathBuf;
8
9/// LLVM IR text generator - works without llvm-sys
10pub struct LLVMTextBackend {
11    module_name: String,
12    /// String constants defined at module level
13    string_constants: Vec<(String, String)>, // (name, value)
14    /// Current string constant counter
15    string_counter: i32,
16    /// Variable mapping for SSA
17    var_map: HashMap<String, VarInfo>,
18    /// Current SSA counter
19    ssa_counter: i32,
20    /// Current label counter
21    label_counter: i32,
22}
23
24#[derive(Clone, Debug)]
25struct VarInfo {
26    ptr: String,    // SSA register holding the pointer
27    ty: String,     // LLVM type string
28    #[allow(dead_code)]
29    is_param: bool, // Whether this is a function parameter
30}
31
32impl LLVMTextBackend {
33    pub fn new(module_name: &str) -> Result<Self> {
34        Ok(Self {
35            module_name: module_name.to_string(),
36            string_constants: Vec::new(),
37            string_counter: 0,
38            var_map: HashMap::new(),
39            ssa_counter: 0,
40            label_counter: 0,
41        })
42    }
43
44    /// Get a fresh SSA register
45    fn fresh_ssa(&mut self) -> String {
46        let reg = format!("%{}", self.ssa_counter);
47        self.ssa_counter += 1;
48        reg
49    }
50
51    /// Get a fresh label
52    fn fresh_label(&mut self, prefix: &str) -> String {
53        let label = format!("{}{}", prefix, self.label_counter);
54        self.label_counter += 1;
55        label
56    }
57
58    /// Compile a program to LLVM IR
59    pub fn compile(&mut self, program: &Program) -> Result<String> {
60        // First pass: collect string constants
61        self.collect_string_constants(program)?;
62
63        // Generate IR
64        let mut ir = String::new();
65
66        // Module header
67        ir.push_str(&format!("; ModuleID = '{}'\n", self.module_name));
68        ir.push_str("source_filename = \"palladium\"\n");
69
70        // Target information for x86_64
71        ir.push_str("target datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n");
72        ir.push_str("target triple = \"x86_64-pc-linux-gnu\"\n\n");
73
74        // External function declarations
75        ir.push_str("; External function declarations\n");
76        ir.push_str("declare i32 @printf(i8*, ...)\n");
77        ir.push_str("declare i8* @malloc(i64)\n");
78        ir.push_str("declare void @free(i8*)\n");
79        ir.push_str("declare i64 @strlen(i8*)\n");
80        ir.push_str("declare i8* @strcpy(i8*, i8*)\n");
81        ir.push_str("declare i8* @strcat(i8*, i8*)\n");
82        ir.push_str("declare i32 @strcmp(i8*, i8*)\n\n");
83
84        // String constants
85        ir.push_str("; String constants\n");
86        ir.push_str(
87            "@.str_fmt = private unnamed_addr constant [4 x i8] c\"%s\\0A\\00\", align 1\n",
88        );
89        ir.push_str(
90            "@.int_fmt = private unnamed_addr constant [6 x i8] c\"%lld\\0A\\00\", align 1\n",
91        );
92
93        // User-defined string constants
94        for (name, value) in &self.string_constants {
95            let escaped = value
96                .replace("\\", "\\\\")
97                .replace("\"", "\\\"")
98                .replace("\n", "\\n");
99            ir.push_str(&format!(
100                "{} = private unnamed_addr constant [{} x i8] c\"{}\\00\", align 1\n",
101                name,
102                value.len() + 1,
103                escaped
104            ));
105        }
106        ir.push('\n');
107
108        // Generate functions
109        for item in &program.items {
110            match item {
111                Item::Function(func) => {
112                    self.ssa_counter = 0; // Reset for each function
113                    self.var_map.clear();
114                    ir.push_str(&self.generate_function(func)?);
115                    ir.push('\n');
116                }
117                _ => {
118                    // Skip other items for now
119                }
120            }
121        }
122
123        Ok(ir)
124    }
125
126    /// Collect all string constants from the program
127    fn collect_string_constants(&mut self, program: &Program) -> Result<()> {
128        for item in &program.items {
129            if let Item::Function(func) = item {
130                self.collect_strings_from_stmts(&func.body);
131            }
132        }
133        Ok(())
134    }
135
136    fn collect_strings_from_stmts(&mut self, stmts: &[Stmt]) {
137        for stmt in stmts {
138            match stmt {
139                Stmt::Expr(expr) | Stmt::Return(Some(expr)) => {
140                    self.collect_strings_from_expr(expr);
141                }
142                Stmt::Let { value, .. } => {
143                    self.collect_strings_from_expr(value);
144                }
145                Stmt::If {
146                    condition,
147                    then_branch,
148                    else_branch,
149                    ..
150                } => {
151                    self.collect_strings_from_expr(condition);
152                    self.collect_strings_from_stmts(then_branch);
153                    if let Some(else_stmts) = else_branch {
154                        self.collect_strings_from_stmts(else_stmts);
155                    }
156                }
157                Stmt::While {
158                    condition, body, ..
159                } => {
160                    self.collect_strings_from_expr(condition);
161                    self.collect_strings_from_stmts(body);
162                }
163                Stmt::For { iter, body, .. } => {
164                    self.collect_strings_from_expr(iter);
165                    self.collect_strings_from_stmts(body);
166                }
167                Stmt::Assign { value, .. } => {
168                    self.collect_strings_from_expr(value);
169                }
170                _ => {}
171            }
172        }
173    }
174
175    fn collect_strings_from_expr(&mut self, expr: &Expr) {
176        match expr {
177            Expr::String(s) => {
178                // Check if we already have this string
179                let exists = self.string_constants.iter().any(|(_, v)| v == s);
180                if !exists {
181                    let name = format!("@.str.{}", self.string_counter);
182                    self.string_counter += 1;
183                    self.string_constants.push((name, s.clone()));
184                }
185            }
186            Expr::Binary { left, right, .. } => {
187                self.collect_strings_from_expr(left);
188                self.collect_strings_from_expr(right);
189            }
190            Expr::Call { func, args, .. } => {
191                self.collect_strings_from_expr(func);
192                for arg in args {
193                    self.collect_strings_from_expr(arg);
194                }
195            }
196            Expr::ArrayLiteral { elements, .. } => {
197                for elem in elements {
198                    self.collect_strings_from_expr(elem);
199                }
200            }
201            Expr::Index { array, index, .. } => {
202                self.collect_strings_from_expr(array);
203                self.collect_strings_from_expr(index);
204            }
205            Expr::Range { start, end, .. } => {
206                self.collect_strings_from_expr(start);
207                self.collect_strings_from_expr(end);
208            }
209            _ => {}
210        }
211    }
212
213    /// Generate LLVM IR for a function
214    fn generate_function(&mut self, func: &Function) -> Result<String> {
215        let mut ir = String::new();
216
217        // Function signature
218        let ret_type = self.type_to_llvm(&func.return_type);
219        ir.push_str(&format!("define {} @{}(", ret_type, func.name));
220
221        // Parameters - values not pointers
222        for (i, param) in func.params.iter().enumerate() {
223            if i > 0 {
224                ir.push_str(", ");
225            }
226            let param_type = self.type_to_llvm(&Some(param.ty.clone()));
227            let param_reg = format!("%{}", param.name);
228            ir.push_str(&format!("{} {}", param_type, param_reg));
229        }
230
231        ir.push_str(") {\n");
232        ir.push_str("entry:\n");
233
234        // Store parameters to local variables
235        for param in &func.params {
236            let param_type = self.type_to_llvm(&Some(param.ty.clone()));
237            let param_reg = format!("%{}", param.name);
238            let alloca = self.fresh_ssa();
239
240            ir.push_str(&format!("  {} = alloca {}\n", alloca, param_type));
241            ir.push_str(&format!(
242                "  store {} {}, {}* {}\n",
243                param_type, param_reg, param_type, alloca
244            ));
245
246            self.var_map.insert(
247                param.name.clone(),
248                VarInfo {
249                    ptr: alloca,
250                    ty: param_type,
251                    is_param: true,
252                },
253            );
254        }
255
256        // Function body
257        for stmt in &func.body {
258            ir.push_str(&self.generate_statement(stmt)?);
259        }
260
261        // Default return if needed
262        if func.return_type.is_none() && !func.body.iter().any(|s| matches!(s, Stmt::Return(_))) {
263            ir.push_str("  ret void\n");
264        }
265
266        ir.push_str("}\n");
267
268        Ok(ir)
269    }
270
271    /// Convert Palladium type to LLVM type
272    #[allow(clippy::only_used_in_recursion)]
273    fn type_to_llvm(&self, ty: &Option<Type>) -> String {
274        match ty {
275            None => "void".to_string(),
276            Some(Type::I32) => "i32".to_string(),
277            Some(Type::I64) => "i64".to_string(),
278            Some(Type::U32) => "i32".to_string(),
279            Some(Type::U64) => "i64".to_string(),
280            Some(Type::Bool) => "i1".to_string(),
281            Some(Type::String) => "i8*".to_string(),
282            Some(Type::Unit) => "void".to_string(),
283            Some(Type::Array(elem_ty, size)) => {
284                match size {
285                    ArraySize::Literal(n) => {
286                        format!(
287                            "[{} x {}]",
288                            n,
289                            self.type_to_llvm(&Some(elem_ty.as_ref().clone()))
290                        )
291                    }
292                    _ => {
293                        // For dynamic or const param arrays, use pointer
294                        format!("{}*", self.type_to_llvm(&Some(elem_ty.as_ref().clone())))
295                    }
296                }
297            }
298            _ => "i8*".to_string(), // Default to pointer for complex types
299        }
300    }
301
302    /// Generate LLVM IR for a statement
303    fn generate_statement(&mut self, stmt: &Stmt) -> Result<String> {
304        let mut ir = String::new();
305
306        match stmt {
307            Stmt::Expr(expr) => {
308                let (expr_ir, _) = self.generate_expression(expr)?;
309                ir.push_str(&expr_ir);
310            }
311
312            Stmt::Let {
313                name, value, ty, ..
314            } => {
315                // Generate the expression first
316                let (expr_ir, result_var, result_type) = self.generate_expression_typed(value)?;
317                ir.push_str(&expr_ir);
318
319                // Determine the type to allocate
320                let alloca_type = if let Some(t) = ty {
321                    self.type_to_llvm(&Some(t.clone()))
322                } else {
323                    // Infer type from expression for better array handling
324                    self.infer_expr_type(value)
325                };
326
327                // Allocate space for the variable
328                let ptr = self.fresh_ssa();
329                ir.push_str(&format!("  {} = alloca {}\n", ptr, alloca_type));
330
331                // Store the value - handle arrays specially
332                if alloca_type.starts_with('[') && alloca_type.ends_with(']') {
333                    // For arrays, we need to copy element by element or use memcpy
334                    // For now, just store the pointer if it's from an array literal
335                    if matches!(value, Expr::ArrayLiteral { .. }) || matches!(value, Expr::ArrayRepeat { .. }) {
336                        // The result_var is already a pointer to the array
337                        // We need to copy the array contents
338                        let array_size = if let Some(start) = alloca_type.find('[') {
339                            if let Some(end) = alloca_type[start+1..].find(' ') {
340                                alloca_type[start+1..start+1+end].parse::<usize>().unwrap_or(1)
341                            } else {
342                                1
343                            }
344                        } else {
345                            1
346                        };
347                        
348                        // Copy each element
349                        for i in 0..array_size {
350                            let src_ptr = self.fresh_ssa();
351                            let dst_ptr = self.fresh_ssa();
352                            let val = self.fresh_ssa();
353                            
354                            ir.push_str(&format!(
355                                "  {} = getelementptr {}, {}* {}, i64 0, i64 {}\n",
356                                src_ptr, alloca_type, alloca_type, result_var, i
357                            ));
358                            ir.push_str(&format!(
359                                "  {} = getelementptr {}, {}* {}, i64 0, i64 {}\n",
360                                dst_ptr, alloca_type, alloca_type, ptr, i
361                            ));
362                            ir.push_str(&format!(
363                                "  {} = load i64, i64* {}\n",
364                                val, src_ptr
365                            ));
366                            ir.push_str(&format!(
367                                "  store i64 {}, i64* {}\n",
368                                val, dst_ptr
369                            ));
370                        }
371                    } else {
372                        // For other array expressions, assume result_var is a pointer
373                        // This is a simplification - proper array assignment would need memcpy
374                        ir.push_str("  ; TODO: Proper array copy for non-literal arrays\n");
375                    }
376                } else {
377                    ir.push_str(&format!(
378                        "  store {} {}, {}* {}\n",
379                        result_type, result_var, alloca_type, ptr
380                    ));
381                }
382
383                // Save variable info
384                self.var_map.insert(
385                    name.clone(),
386                    VarInfo {
387                        ptr,
388                        ty: alloca_type,
389                        is_param: false,
390                    },
391                );
392            }
393
394            Stmt::Return(Some(expr)) => {
395                let (expr_ir, result) = self.generate_expression(expr)?;
396                ir.push_str(&expr_ir);
397
398                // Infer return type from expression
399                let ret_type = self.infer_expr_type(expr);
400                ir.push_str(&format!("  ret {} {}\n", ret_type, result));
401            }
402
403            Stmt::Return(None) => {
404                ir.push_str("  ret void\n");
405            }
406
407            Stmt::If {
408                condition,
409                then_branch,
410                else_branch,
411                ..
412            } => {
413                let then_label = self.fresh_label("then");
414                let else_label = self.fresh_label("else");
415                let end_label = self.fresh_label("endif");
416
417                let (cond_ir, cond_result) = self.generate_expression(condition)?;
418                ir.push_str(&cond_ir);
419
420                if else_branch.is_some() {
421                    ir.push_str(&format!(
422                        "  br i1 {}, label %{}, label %{}\n",
423                        cond_result, then_label, else_label
424                    ));
425                } else {
426                    ir.push_str(&format!(
427                        "  br i1 {}, label %{}, label %{}\n",
428                        cond_result, then_label, end_label
429                    ));
430                }
431
432                // Then branch
433                ir.push_str(&format!("{}:\n", then_label));
434                for stmt in then_branch {
435                    ir.push_str(&self.generate_statement(stmt)?);
436                }
437                ir.push_str(&format!("  br label %{}\n", end_label));
438
439                // Else branch
440                if let Some(else_stmts) = else_branch {
441                    ir.push_str(&format!("{}:\n", else_label));
442                    for stmt in else_stmts {
443                        ir.push_str(&self.generate_statement(stmt)?);
444                    }
445                    ir.push_str(&format!("  br label %{}\n", end_label));
446                }
447
448                // End label
449                ir.push_str(&format!("{}:\n", end_label));
450            }
451
452            Stmt::While {
453                condition, body, ..
454            } => {
455                let cond_label = self.fresh_label("while_cond");
456                let body_label = self.fresh_label("while_body");
457                let end_label = self.fresh_label("while_end");
458
459                // Jump to condition check
460                ir.push_str(&format!("  br label %{}\n", cond_label));
461
462                // Condition label
463                ir.push_str(&format!("{}:\n", cond_label));
464                let (cond_ir, cond_result) = self.generate_expression(condition)?;
465                ir.push_str(&cond_ir);
466                ir.push_str(&format!(
467                    "  br i1 {}, label %{}, label %{}\n",
468                    cond_result, body_label, end_label
469                ));
470
471                // Body label
472                ir.push_str(&format!("{}:\n", body_label));
473                for stmt in body {
474                    ir.push_str(&self.generate_statement(stmt)?);
475                }
476                ir.push_str(&format!("  br label %{}\n", cond_label));
477
478                // End label
479                ir.push_str(&format!("{}:\n", end_label));
480            }
481
482            Stmt::For {
483                var, iter, body, ..
484            } => {
485                match iter {
486                    // Handle range iteration
487                    Expr::Range { start, end, .. } => {
488                        let (start_ir, start_val) = self.generate_expression(start)?;
489                        let (end_ir, end_val) = self.generate_expression(end)?;
490                        ir.push_str(&start_ir);
491                        ir.push_str(&end_ir);
492
493                        // Allocate loop variable
494                        let loop_var_ptr = self.fresh_ssa();
495                        ir.push_str(&format!("  {} = alloca i64\n", loop_var_ptr));
496                        ir.push_str(&format!(
497                            "  store i64 {}, i64* {}\n",
498                            start_val, loop_var_ptr
499                        ));
500
501                        self.var_map.insert(
502                            var.clone(),
503                            VarInfo {
504                                ptr: loop_var_ptr.clone(),
505                                ty: "i64".to_string(),
506                                is_param: false,
507                            },
508                        );
509
510                        let cond_label = self.fresh_label("for_cond");
511                        let body_label = self.fresh_label("for_body");
512                        let inc_label = self.fresh_label("for_inc");
513                        let end_label = self.fresh_label("for_end");
514
515                        // Jump to condition
516                        ir.push_str(&format!("  br label %{}\n", cond_label));
517
518                        // Condition: check if i < end
519                        ir.push_str(&format!("{}:\n", cond_label));
520                        let i_val = self.fresh_ssa();
521                        ir.push_str(&format!("  {} = load i64, i64* {}\n", i_val, loop_var_ptr));
522                        let cmp = self.fresh_ssa();
523                        ir.push_str(&format!(
524                            "  {} = icmp slt i64 {}, {}\n",
525                            cmp, i_val, end_val
526                        ));
527                        ir.push_str(&format!(
528                            "  br i1 {}, label %{}, label %{}\n",
529                            cmp, body_label, end_label
530                        ));
531
532                        // Body
533                        ir.push_str(&format!("{}:\n", body_label));
534                        for stmt in body {
535                            ir.push_str(&self.generate_statement(stmt)?);
536                        }
537                        ir.push_str(&format!("  br label %{}\n", inc_label));
538
539                        // Increment
540                        ir.push_str(&format!("{}:\n", inc_label));
541                        let curr_val = self.fresh_ssa();
542                        let next_val = self.fresh_ssa();
543                        ir.push_str(&format!(
544                            "  {} = load i64, i64* {}\n",
545                            curr_val, loop_var_ptr
546                        ));
547                        ir.push_str(&format!("  {} = add i64 {}, 1\n", next_val, curr_val));
548                        ir.push_str(&format!(
549                            "  store i64 {}, i64* {}\n",
550                            next_val, loop_var_ptr
551                        ));
552                        ir.push_str(&format!("  br label %{}\n", cond_label));
553
554                        // End
555                        ir.push_str(&format!("{}:\n", end_label));
556                    }
557                    
558                    // Handle array iteration
559                    Expr::Ident(array_name) => {
560                        if let Some(var_info) = self.var_map.get(array_name).cloned() {
561                            // Check if it's an array type
562                            if var_info.ty.starts_with('[') && var_info.ty.contains(" x ") {
563                                // Extract array size and element type
564                                let array_type = &var_info.ty;
565                                let size_end = array_type.find(" x ").unwrap();
566                                let size: usize = array_type[1..size_end].parse().unwrap_or(0);
567                                let elem_type = array_type[size_end + 3..array_type.len() - 1].to_string();
568                                
569                                // Allocate index variable
570                                let idx_ptr = self.fresh_ssa();
571                                ir.push_str(&format!("  {} = alloca i64\n", idx_ptr));
572                                ir.push_str(&format!("  store i64 0, i64* {}\n", idx_ptr));
573                                
574                                // Allocate loop variable
575                                let loop_var_ptr = self.fresh_ssa();
576                                ir.push_str(&format!("  {} = alloca {}\n", loop_var_ptr, elem_type));
577                                
578                                self.var_map.insert(
579                                    var.clone(),
580                                    VarInfo {
581                                        ptr: loop_var_ptr.clone(),
582                                        ty: elem_type.clone(),
583                                        is_param: false,
584                                    },
585                                );
586                                
587                                let cond_label = self.fresh_label("for_cond");
588                                let body_label = self.fresh_label("for_body");
589                                let inc_label = self.fresh_label("for_inc");
590                                let end_label = self.fresh_label("for_end");
591                                
592                                // Jump to condition
593                                ir.push_str(&format!("  br label %{}\n", cond_label));
594                                
595                                // Condition: check if idx < size
596                                ir.push_str(&format!("{}:\n", cond_label));
597                                let idx_val = self.fresh_ssa();
598                                ir.push_str(&format!("  {} = load i64, i64* {}\n", idx_val, idx_ptr));
599                                let cmp = self.fresh_ssa();
600                                ir.push_str(&format!("  {} = icmp slt i64 {}, {}\n", cmp, idx_val, size));
601                                ir.push_str(&format!(
602                                    "  br i1 {}, label %{}, label %{}\n",
603                                    cmp, body_label, end_label
604                                ));
605                                
606                                // Body: load array element into loop variable
607                                ir.push_str(&format!("{}:\n", body_label));
608                                let elem_ptr = self.fresh_ssa();
609                                let elem_val = self.fresh_ssa();
610                                ir.push_str(&format!(
611                                    "  {} = getelementptr {}, {}* {}, i64 0, i64 {}\n",
612                                    elem_ptr, array_type, array_type, var_info.ptr, idx_val
613                                ));
614                                ir.push_str(&format!(
615                                    "  {} = load {}, {}* {}\n",
616                                    elem_val, elem_type, elem_type, elem_ptr
617                                ));
618                                ir.push_str(&format!(
619                                    "  store {} {}, {}* {}\n",
620                                    elem_type, elem_val, elem_type, loop_var_ptr
621                                ));
622                                
623                                // Execute loop body
624                                for stmt in body {
625                                    ir.push_str(&self.generate_statement(stmt)?);
626                                }
627                                ir.push_str(&format!("  br label %{}\n", inc_label));
628                                
629                                // Increment index
630                                ir.push_str(&format!("{}:\n", inc_label));
631                                let curr_idx = self.fresh_ssa();
632                                let next_idx = self.fresh_ssa();
633                                ir.push_str(&format!("  {} = load i64, i64* {}\n", curr_idx, idx_ptr));
634                                ir.push_str(&format!("  {} = add i64 {}, 1\n", next_idx, curr_idx));
635                                ir.push_str(&format!("  store i64 {}, i64* {}\n", next_idx, idx_ptr));
636                                ir.push_str(&format!("  br label %{}\n", cond_label));
637                                
638                                // End
639                                ir.push_str(&format!("{}:\n", end_label));
640                            } else {
641                                return Err(CompileError::Generic(format!(
642                                    "Cannot iterate over non-array type: {}",
643                                    var_info.ty
644                                )));
645                            }
646                        } else {
647                            return Err(CompileError::Generic(format!(
648                                "Undefined variable: {}",
649                                array_name
650                            )));
651                        }
652                    }
653                    
654                    // Handle array literal iteration
655                    Expr::ArrayLiteral { elements, .. } => {
656                        // First, generate a temporary array
657                        let elem_type = "i64"; // For now, assume i64 arrays
658                        let array_type = format!("[{} x {}]", elements.len(), elem_type);
659                        let temp_array = self.fresh_ssa();
660                        
661                        ir.push_str(&format!("  {} = alloca {}\n", temp_array, array_type));
662                        
663                        // Initialize array elements
664                        for (i, elem) in elements.iter().enumerate() {
665                            let (elem_ir, elem_val) = self.generate_expression(elem)?;
666                            ir.push_str(&elem_ir);
667                            let ptr = self.fresh_ssa();
668                            ir.push_str(&format!(
669                                "  {} = getelementptr {}, {}* {}, i64 0, i64 {}\n",
670                                ptr, array_type, array_type, temp_array, i
671                            ));
672                            ir.push_str(&format!(
673                                "  store {} {}, {}* {}\n",
674                                elem_type, elem_val, elem_type, ptr
675                            ));
676                        }
677                        
678                        // Now iterate over the temporary array
679                        // Similar code to array iteration above...
680                        let idx_ptr = self.fresh_ssa();
681                        ir.push_str(&format!("  {} = alloca i64\n", idx_ptr));
682                        ir.push_str(&format!("  store i64 0, i64* {}\n", idx_ptr));
683                        
684                        let loop_var_ptr = self.fresh_ssa();
685                        ir.push_str(&format!("  {} = alloca {}\n", loop_var_ptr, elem_type));
686                        
687                        self.var_map.insert(
688                            var.clone(),
689                            VarInfo {
690                                ptr: loop_var_ptr.clone(),
691                                ty: elem_type.to_string(),
692                                is_param: false,
693                            },
694                        );
695                        
696                        let cond_label = self.fresh_label("for_cond");
697                        let body_label = self.fresh_label("for_body");
698                        let inc_label = self.fresh_label("for_inc");
699                        let end_label = self.fresh_label("for_end");
700                        
701                        ir.push_str(&format!("  br label %{}\n", cond_label));
702                        
703                        ir.push_str(&format!("{}:\n", cond_label));
704                        let idx_val = self.fresh_ssa();
705                        ir.push_str(&format!("  {} = load i64, i64* {}\n", idx_val, idx_ptr));
706                        let cmp = self.fresh_ssa();
707                        ir.push_str(&format!("  {} = icmp slt i64 {}, {}\n", cmp, idx_val, elements.len()));
708                        ir.push_str(&format!(
709                            "  br i1 {}, label %{}, label %{}\n",
710                            cmp, body_label, end_label
711                        ));
712                        
713                        ir.push_str(&format!("{}:\n", body_label));
714                        let elem_ptr = self.fresh_ssa();
715                        let elem_val = self.fresh_ssa();
716                        ir.push_str(&format!(
717                            "  {} = getelementptr {}, {}* {}, i64 0, i64 {}\n",
718                            elem_ptr, array_type, array_type, temp_array, idx_val
719                        ));
720                        ir.push_str(&format!(
721                            "  {} = load {}, {}* {}\n",
722                            elem_val, elem_type, elem_type, elem_ptr
723                        ));
724                        ir.push_str(&format!(
725                            "  store {} {}, {}* {}\n",
726                            elem_type, elem_val, elem_type, loop_var_ptr
727                        ));
728                        
729                        for stmt in body {
730                            ir.push_str(&self.generate_statement(stmt)?);
731                        }
732                        ir.push_str(&format!("  br label %{}\n", inc_label));
733                        
734                        ir.push_str(&format!("{}:\n", inc_label));
735                        let curr_idx = self.fresh_ssa();
736                        let next_idx = self.fresh_ssa();
737                        ir.push_str(&format!("  {} = load i64, i64* {}\n", curr_idx, idx_ptr));
738                        ir.push_str(&format!("  {} = add i64 {}, 1\n", next_idx, curr_idx));
739                        ir.push_str(&format!("  store i64 {}, i64* {}\n", next_idx, idx_ptr));
740                        ir.push_str(&format!("  br label %{}\n", cond_label));
741                        
742                        ir.push_str(&format!("{}:\n", end_label));
743                    }
744                    
745                    _ => {
746                        return Err(CompileError::Generic(
747                            "Unsupported iterator type in for loop".to_string(),
748                        ));
749                    }
750                }
751            }
752
753            Stmt::Assign { target, value, .. } => {
754                let (value_ir, value_var, value_type) = self.generate_expression_typed(value)?;
755                ir.push_str(&value_ir);
756
757                match target {
758                    AssignTarget::Ident(name) => {
759                        if let Some(var_info) = self.var_map.get(name).cloned() {
760                            ir.push_str(&format!(
761                                "  store {} {}, {}* {}\n",
762                                value_type, value_var, var_info.ty, var_info.ptr
763                            ));
764                        } else {
765                            return Err(CompileError::Generic(format!(
766                                "Undefined variable: {}",
767                                name
768                            )));
769                        }
770                    }
771                    AssignTarget::Index { array, index } => {
772                        let (index_ir, index_var) = self.generate_expression(index)?;
773                        ir.push_str(&index_ir);
774
775                        if let Expr::Ident(array_name) = array.as_ref() {
776                            if let Some(var_info) = self.var_map.get(array_name).cloned() {
777                                let ptr = self.fresh_ssa();
778                                // Extract array size from type string
779                                if let Some(array_type) = var_info
780                                    .ty
781                                    .strip_prefix('[')
782                                    .and_then(|s| s.find(" x "))
783                                    .map(|i| &var_info.ty[1..i])
784                                {
785                                    let _size: usize = array_type.parse().unwrap_or(5);
786                                    ir.push_str(&format!(
787                                        "  {} = getelementptr {}, {}* {}, i64 0, i64 {}\n",
788                                        ptr, var_info.ty, var_info.ty, var_info.ptr, index_var
789                                    ));
790                                    ir.push_str(&format!(
791                                        "  store {} {}, {}* {}\n",
792                                        value_type, value_var, value_type, ptr
793                                    ));
794                                }
795                            }
796                        }
797                    }
798                    AssignTarget::FieldAccess { object, field: _ } => {
799                        // Generate code to get the field pointer
800                        let (obj_ir, obj_var) = self.generate_expression(object)?;
801                        ir.push_str(&obj_ir);
802                        
803                        // TODO: Look up struct definition to find field index
804                        let field_idx = 0; // Placeholder
805                        let field_ptr = self.fresh_ssa();
806                        
807                        // Infer struct type
808                        let struct_type = if let Expr::Ident(name) = object.as_ref() {
809                            if let Some(var_info) = self.var_map.get(name) {
810                                var_info.ty.clone()
811                            } else {
812                                "%struct.Unknown".to_string()
813                            }
814                        } else {
815                            "%struct.Unknown".to_string()
816                        };
817                        
818                        ir.push_str(&format!(
819                            "  {} = getelementptr {}, {}* {}, i32 0, i32 {}\n",
820                            field_ptr, struct_type, struct_type, obj_var, field_idx
821                        ));
822                        ir.push_str(&format!(
823                            "  store {} {}, {}* {}\n",
824                            value_type, value_var, value_type, field_ptr
825                        ));
826                    }
827                    AssignTarget::Deref { expr } => {
828                        let (ptr_ir, ptr_var) = self.generate_expression(expr)?;
829                        ir.push_str(&ptr_ir);
830                        ir.push_str(&format!(
831                            "  store {} {}, {}* {}\n",
832                            value_type, value_var, value_type, ptr_var
833                        ));
834                    }
835                }
836            }
837
838            Stmt::Break { .. } => {
839                // Generate jump to the end of the current loop
840                // For now, we'll use a placeholder since we need loop context
841                ir.push_str("  ; TODO: Implement break with proper loop context\n");
842                ir.push_str("  br label %loop_end_placeholder\n");
843            }
844            
845            Stmt::Continue { .. } => {
846                // Generate jump to the increment part of the current loop
847                // For now, we'll use a placeholder since we need loop context
848                ir.push_str("  ; TODO: Implement continue with proper loop context\n");
849                ir.push_str("  br label %loop_inc_placeholder\n");
850            }
851            
852            Stmt::Match { expr, arms, .. } => {
853                // Generate switch-like control flow for match
854                let (expr_ir, _expr_var) = self.generate_expression(expr)?;
855                ir.push_str(&expr_ir);
856                
857                let end_label = self.fresh_label("match_end");
858                
859                // For now, generate a simple if-else chain
860                // TODO: Implement proper pattern matching
861                for (i, arm) in arms.iter().enumerate() {
862                    let arm_label = self.fresh_label(&format!("match_arm{}", i));
863                    let next_label = if i + 1 < arms.len() {
864                        self.fresh_label(&format!("match_arm{}", i + 1))
865                    } else {
866                        end_label.clone()
867                    };
868                    
869                    // Simple pattern matching for now
870                    match &arm.pattern {
871                        Pattern::Wildcard => {
872                            // Always matches
873                            ir.push_str(&format!("  br label %{}\n", arm_label));
874                        }
875                        Pattern::Ident(_) => {
876                            // Bind the value and match
877                            ir.push_str(&format!("  br label %{}\n", arm_label));
878                        }
879                        _ => {
880                            // TODO: Implement enum pattern matching
881                            ir.push_str("  ; TODO: Complex pattern matching\n");
882                            ir.push_str(&format!("  br label %{}\n", next_label));
883                        }
884                    }
885                    
886                    ir.push_str(&format!("{}:\n", arm_label));
887                    for stmt in &arm.body {
888                        ir.push_str(&self.generate_statement(stmt)?);
889                    }
890                    ir.push_str(&format!("  br label %{}\n", end_label));
891                }
892                
893                ir.push_str(&format!("{}:\n", end_label));
894            }
895            
896            Stmt::Unsafe { body, .. } => {
897                // In LLVM IR, there's no explicit unsafe block
898                // Just generate the body statements
899                ir.push_str("  ; Unsafe block\n");
900                for stmt in body {
901                    ir.push_str(&self.generate_statement(stmt)?);
902                }
903            }
904        }
905
906        Ok(ir)
907    }
908
909    /// Generate LLVM IR for an expression, returning (IR code, result value, result type)
910    fn generate_expression_typed(&mut self, expr: &Expr) -> Result<(String, String, String)> {
911        let (ir, val) = self.generate_expression(expr)?;
912        let ty = self.infer_expr_type(expr);
913        Ok((ir, val, ty))
914    }
915
916    /// Generate LLVM IR for an expression
917    /// Returns (IR code, result variable/value)
918    fn generate_expression(&mut self, expr: &Expr) -> Result<(String, String)> {
919        let mut ir = String::new();
920
921        match expr {
922            Expr::Integer(n) => Ok((String::new(), n.to_string())),
923
924            Expr::Bool(b) => Ok((String::new(), if *b { "1" } else { "0" }.to_string())),
925
926            Expr::String(s) => {
927                // Find the pre-collected string constant
928                let const_name = self
929                    .string_constants
930                    .iter()
931                    .find(|(_, v)| v == s)
932                    .map(|(n, _)| n.clone())
933                    .unwrap_or_else(|| "@.str.unknown".to_string());
934
935                let ptr_var = self.fresh_ssa();
936                ir.push_str(&format!(
937                    "  {} = getelementptr [{} x i8], [{} x i8]* {}, i32 0, i32 0\n",
938                    ptr_var,
939                    s.len() + 1,
940                    s.len() + 1,
941                    const_name
942                ));
943
944                Ok((ir, ptr_var))
945            }
946
947            Expr::Ident(name) => {
948                if let Some(var_info) = self.var_map.get(name).cloned() {
949                    // Check if this is an array type
950                    if var_info.ty.starts_with('[') && var_info.ty.ends_with(']') {
951                        // For arrays, return the pointer directly - don't load
952                        Ok((ir, var_info.ptr))
953                    } else {
954                        let load_var = self.fresh_ssa();
955                        ir.push_str(&format!(
956                            "  {} = load {}, {}* {}\n",
957                            load_var, var_info.ty, var_info.ty, var_info.ptr
958                        ));
959                        Ok((ir, load_var))
960                    }
961                } else {
962                    Err(CompileError::UndefinedVariable {
963                        name: name.clone(),
964                        span: None,
965                    })
966                }
967            }
968
969            Expr::Binary {
970                left, op, right, ..
971            } => {
972                let (left_ir, left_var) = self.generate_expression(left)?;
973                let (right_ir, right_var) = self.generate_expression(right)?;
974
975                ir.push_str(&left_ir);
976                ir.push_str(&right_ir);
977
978                let result_var = self.fresh_ssa();
979
980                let op_str = match op {
981                    BinOp::Add => "add",
982                    BinOp::Sub => "sub",
983                    BinOp::Mul => "mul",
984                    BinOp::Div => "sdiv",
985                    BinOp::Mod => "srem",
986                    BinOp::Lt => "icmp slt",
987                    BinOp::Le => "icmp sle",
988                    BinOp::Gt => "icmp sgt",
989                    BinOp::Ge => "icmp sge",
990                    BinOp::Eq => "icmp eq",
991                    BinOp::Ne => "icmp ne",
992                    _ => {
993                        return Err(CompileError::Generic(
994                            "Unsupported binary operator".to_string(),
995                        ))
996                    }
997                };
998
999                // Determine operand type (for now, assume i64 for arithmetic)
1000                // All operations work on i64 for now
1001                let op_type = "i64";
1002
1003                ir.push_str(&format!(
1004                    "  {} = {} {} {}, {}\n",
1005                    result_var, op_str, op_type, left_var, right_var
1006                ));
1007
1008                Ok((ir, result_var))
1009            }
1010
1011            Expr::ArrayLiteral { elements, .. } => {
1012                // Generate array literal
1013                let elem_type = "i64"; // For now, assume i64 arrays
1014                let array_type = format!("[{} x {}]", elements.len(), elem_type);
1015
1016                // Allocate array on stack
1017                let array_var = self.fresh_ssa();
1018                ir.push_str(&format!("  {} = alloca {}\n", array_var, array_type));
1019
1020                // Initialize elements
1021                for (i, elem) in elements.iter().enumerate() {
1022                    let (elem_ir, elem_val) = self.generate_expression(elem)?;
1023                    ir.push_str(&elem_ir);
1024
1025                    let ptr = self.fresh_ssa();
1026                    ir.push_str(&format!(
1027                        "  {} = getelementptr {}, {}* {}, i64 0, i64 {}\n",
1028                        ptr, array_type, array_type, array_var, i
1029                    ));
1030                    ir.push_str(&format!(
1031                        "  store {} {}, {}* {}\n",
1032                        elem_type, elem_val, elem_type, ptr
1033                    ));
1034                }
1035
1036                Ok((ir, array_var))
1037            }
1038
1039            Expr::Index { array, index, .. } => {
1040                let (idx_ir, idx_var) = self.generate_expression(index)?;
1041                ir.push_str(&idx_ir);
1042
1043                // Handle array expression - could be an identifier or other expression
1044                if let Expr::Ident(name) = array.as_ref() {
1045                    if let Some(var_info) = self.var_map.get(name).cloned() {
1046                        let ptr = self.fresh_ssa();
1047                        let val = self.fresh_ssa();
1048
1049                        // Use the actual array type from var_info
1050                        ir.push_str(&format!(
1051                            "  {} = getelementptr {}, {}* {}, i64 0, i64 {}\n",
1052                            ptr, var_info.ty, var_info.ty, var_info.ptr, idx_var
1053                        ));
1054                        ir.push_str(&format!("  {} = load i64, i64* {}\n", val, ptr));
1055
1056                        Ok((ir, val))
1057                    } else {
1058                        Err(CompileError::Generic(format!("Undefined array: {}", name)))
1059                    }
1060                } else {
1061                    // For other array expressions, we need to evaluate them
1062                    let (array_ir, array_var) = self.generate_expression(array)?;
1063                    ir.push_str(&array_ir);
1064
1065                    let ptr = self.fresh_ssa();
1066                    let val = self.fresh_ssa();
1067
1068                    // TODO: Properly infer array type
1069                    ir.push_str(&format!(
1070                        "  {} = getelementptr [5 x i64], [5 x i64]* {}, i64 0, i64 {}\n",
1071                        ptr, array_var, idx_var
1072                    ));
1073                    ir.push_str(&format!("  {} = load i64, i64* {}\n", val, ptr));
1074
1075                    Ok((ir, val))
1076                }
1077            }
1078
1079            Expr::Call { func, args, .. } => {
1080                if let Expr::Ident(func_name) = func.as_ref() {
1081                    match func_name.as_str() {
1082                        "print" => {
1083                            if args.len() == 1 {
1084                                let (arg_ir, arg_var) = self.generate_expression(&args[0])?;
1085                                ir.push_str(&arg_ir);
1086                                ir.push_str(&format!("  call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str_fmt, i32 0, i32 0), i8* {})\n", arg_var));
1087                            }
1088                            Ok((ir, "0".to_string())) // Dummy return
1089                        }
1090                        "print_int" => {
1091                            if args.len() == 1 {
1092                                let (arg_ir, arg_var) = self.generate_expression(&args[0])?;
1093                                ir.push_str(&arg_ir);
1094                                ir.push_str(&format!("  call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.int_fmt, i32 0, i32 0), i64 {})\n", arg_var));
1095                            }
1096                            Ok((ir, "0".to_string())) // Dummy return
1097                        }
1098                        _ => {
1099                            // User-defined function call
1100                            let mut arg_vars = Vec::new();
1101                            let mut arg_types = Vec::new();
1102
1103                            for arg in args {
1104                                let (arg_ir, arg_var, arg_type) =
1105                                    self.generate_expression_typed(arg)?;
1106                                ir.push_str(&arg_ir);
1107                                arg_vars.push(arg_var);
1108                                arg_types.push(arg_type);
1109                            }
1110
1111                            let result_var = self.fresh_ssa();
1112
1113                            // TODO: Look up actual function return type
1114                            let ret_type = "i64"; // Default to i64
1115
1116                            ir.push_str(&format!(
1117                                "  {} = call {} @{}(",
1118                                result_var, ret_type, func_name
1119                            ));
1120                            for (i, (arg_var, arg_type)) in
1121                                arg_vars.iter().zip(arg_types.iter()).enumerate()
1122                            {
1123                                if i > 0 {
1124                                    ir.push_str(", ");
1125                                }
1126                                ir.push_str(&format!("{} {}", arg_type, arg_var));
1127                            }
1128                            ir.push_str(")\n");
1129
1130                            Ok((ir, result_var))
1131                        }
1132                    }
1133                } else {
1134                    Err(CompileError::Generic(
1135                        "Complex function calls not yet supported".to_string(),
1136                    ))
1137                }
1138            }
1139
1140            Expr::Range { start, end, .. } => {
1141                // Ranges are handled specially in for loops
1142                let (start_ir, start_val) = self.generate_expression(start)?;
1143                let (end_ir, end_val) = self.generate_expression(end)?;
1144                ir.push_str(&start_ir);
1145                ir.push_str(&end_ir);
1146                Ok((ir, format!("range({}, {})", start_val, end_val)))
1147            }
1148
1149            Expr::StructLiteral { name, fields, .. } => {
1150                // Allocate struct on stack
1151                let struct_type = format!("%struct.{}", name);
1152                let struct_var = self.fresh_ssa();
1153                ir.push_str(&format!("  {} = alloca {}\n", struct_var, struct_type));
1154                
1155                // Initialize fields
1156                for (i, (_field_name, field_expr)) in fields.iter().enumerate() {
1157                    let (field_ir, field_val) = self.generate_expression(field_expr)?;
1158                    ir.push_str(&field_ir);
1159                    
1160                    let field_ptr = self.fresh_ssa();
1161                    ir.push_str(&format!(
1162                        "  {} = getelementptr {}, {}* {}, i32 0, i32 {}\n",
1163                        field_ptr, struct_type, struct_type, struct_var, i
1164                    ));
1165                    
1166                    let field_type = self.infer_expr_type(field_expr);
1167                    ir.push_str(&format!(
1168                        "  store {} {}, {}* {}\n",
1169                        field_type, field_val, field_type, field_ptr
1170                    ));
1171                }
1172                
1173                Ok((ir, struct_var))
1174            }
1175            
1176            Expr::FieldAccess { object, field: _, .. } => {
1177                let (obj_ir, obj_var) = self.generate_expression(object)?;
1178                ir.push_str(&obj_ir);
1179                
1180                // TODO: Look up struct definition to find field index
1181                let field_idx = 0; // Placeholder
1182                let field_ptr = self.fresh_ssa();
1183                let field_val = self.fresh_ssa();
1184                
1185                // Infer struct type from object expression
1186                let struct_type = if let Expr::Ident(name) = object.as_ref() {
1187                    if let Some(var_info) = self.var_map.get(name) {
1188                        var_info.ty.clone()
1189                    } else {
1190                        "%struct.Unknown".to_string()
1191                    }
1192                } else {
1193                    "%struct.Unknown".to_string()
1194                };
1195                
1196                ir.push_str(&format!(
1197                    "  {} = getelementptr {}, {}* {}, i32 0, i32 {}\n",
1198                    field_ptr, struct_type, struct_type, obj_var, field_idx
1199                ));
1200                ir.push_str(&format!("  {} = load i64, i64* {}\n", field_val, field_ptr));
1201                
1202                Ok((ir, field_val))
1203            }
1204            
1205            Expr::ArrayRepeat { value, count, .. } => {
1206                let (count_ir, _count_val) = self.generate_expression(count)?;
1207                ir.push_str(&count_ir);
1208                
1209                // For compile-time constant arrays
1210                if let Expr::Integer(n) = count.as_ref() {
1211                    let elem_type = "i64";
1212                    let array_type = format!("[{} x {}]", n, elem_type);
1213                    let array_var = self.fresh_ssa();
1214                    
1215                    ir.push_str(&format!("  {} = alloca {}\n", array_var, array_type));
1216                    
1217                    // Generate value once
1218                    let (val_ir, val_var) = self.generate_expression(value)?;
1219                    ir.push_str(&val_ir);
1220                    
1221                    // Initialize all elements
1222                    for i in 0..*n {
1223                        let ptr = self.fresh_ssa();
1224                        ir.push_str(&format!(
1225                            "  {} = getelementptr {}, {}* {}, i64 0, i64 {}\n",
1226                            ptr, array_type, array_type, array_var, i
1227                        ));
1228                        ir.push_str(&format!(
1229                            "  store {} {}, {}* {}\n",
1230                            elem_type, val_var, elem_type, ptr
1231                        ));
1232                    }
1233                    
1234                    Ok((ir, array_var))
1235                } else {
1236                    Err(CompileError::Generic(
1237                        "Dynamic array repeat not yet supported".to_string()
1238                    ))
1239                }
1240            }
1241            
1242            Expr::Unary { op, operand, .. } => {
1243                let (op_ir, op_var) = self.generate_expression(operand)?;
1244                ir.push_str(&op_ir);
1245                
1246                let result_var = self.fresh_ssa();
1247                
1248                match op {
1249                    UnaryOp::Neg => {
1250                        ir.push_str(&format!(
1251                            "  {} = sub i64 0, {}\n",
1252                            result_var, op_var
1253                        ));
1254                    }
1255                    UnaryOp::Not => {
1256                        ir.push_str(&format!(
1257                            "  {} = xor i1 {}, true\n",
1258                            result_var, op_var
1259                        ));
1260                    }
1261                }
1262                
1263                Ok((ir, result_var))
1264            }
1265            
1266            Expr::Reference { mutable: _, expr, .. } => {
1267                // For now, just return the address of the expression
1268                if let Expr::Ident(name) = expr.as_ref() {
1269                    if let Some(var_info) = self.var_map.get(name) {
1270                        Ok((String::new(), var_info.ptr.clone()))
1271                    } else {
1272                        Err(CompileError::Generic(format!("Undefined variable: {}", name)))
1273                    }
1274                } else {
1275                    Err(CompileError::Generic(
1276                        "Complex reference expressions not yet supported".to_string()
1277                    ))
1278                }
1279            }
1280            
1281            Expr::Deref { expr, .. } => {
1282                let (expr_ir, expr_var) = self.generate_expression(expr)?;
1283                ir.push_str(&expr_ir);
1284                
1285                let result_var = self.fresh_ssa();
1286                ir.push_str(&format!("  {} = load i64, i64* {}\n", result_var, expr_var));
1287                
1288                Ok((ir, result_var))
1289            }
1290            
1291            _ => {
1292                // TODO: Implement EnumConstructor, Question, MacroInvocation, Await
1293                Ok((String::new(), "0".to_string()))
1294            }
1295        }
1296    }
1297
1298    /// Infer the LLVM type of an expression
1299    fn infer_expr_type(&self, expr: &Expr) -> String {
1300        match expr {
1301            Expr::Integer(_) => "i64".to_string(),
1302            Expr::Bool(_) => "i1".to_string(),
1303            Expr::String(_) => "i8*".to_string(),
1304            Expr::ArrayLiteral { elements, .. } => {
1305                format!("[{} x i64]", elements.len())
1306            }
1307            Expr::ArrayRepeat { count, .. } => {
1308                if let Expr::Integer(n) = count.as_ref() {
1309                    format!("[{} x i64]", n)
1310                } else {
1311                    "i64".to_string() // Default for dynamic arrays
1312                }
1313            }
1314            Expr::Binary { op, .. } => {
1315                if matches!(op, BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Eq | BinOp::Ne) {
1316                    "i1".to_string()
1317                } else {
1318                    "i64".to_string()
1319                }
1320            }
1321            Expr::Call { .. } => "i64".to_string(), // Default
1322            Expr::Ident(name) => {
1323                if let Some(var_info) = self.var_map.get(name) {
1324                    var_info.ty.clone()
1325                } else {
1326                    "i64".to_string() // Default
1327                }
1328            }
1329            _ => "i64".to_string(), // Default
1330        }
1331    }
1332
1333    /// Write the generated LLVM IR to a file
1334    pub fn write_output(&self, ir: &str) -> Result<PathBuf> {
1335        let build_dir = PathBuf::from("build_output");
1336        if !build_dir.exists() {
1337            std::fs::create_dir_all(&build_dir)?;
1338        }
1339
1340        let output_path = build_dir.join(format!("{}.ll", self.module_name));
1341        std::fs::write(&output_path, ir)?;
1342
1343        Ok(output_path)
1344    }
1345}