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/bin/ruchy.rs
Line
Count
Source
1
#![allow(clippy::print_stdout)]
2
#![allow(clippy::print_stderr)]
3
#![allow(clippy::cast_precision_loss)]
4
#![allow(clippy::cast_possible_truncation)]
5
#![allow(clippy::unwrap_used)]
6
#![allow(clippy::uninlined_format_args)]
7
#![allow(clippy::format_push_string)]
8
#![allow(clippy::match_same_arms)]
9
#![allow(clippy::fn_params_excessive_bools)]
10
#![allow(clippy::too_many_lines)]
11
#![allow(clippy::redundant_field_names)]
12
#![allow(clippy::too_many_arguments)]
13
#![allow(clippy::collapsible_else_if)]
14
#![allow(clippy::field_reassign_with_default)]
15
#![allow(clippy::format_in_format_args)]
16
#![allow(clippy::items_after_statements)]
17
#![allow(dead_code)]
18
19
use anyhow::Result;
20
use clap::{Parser, Subcommand};
21
// use colored::Colorize; // Unused after refactoring
22
use ruchy::{runtime::repl::Repl, Parser as RuchyParser};
23
use std::fs;
24
use std::io::{self, IsTerminal, Read};
25
use std::path::{Path, PathBuf};
26
27
28
mod handlers;
29
use handlers::{
30
    handle_parse_command, handle_transpile_command, handle_run_command,
31
    handle_eval_command, handle_file_execution, handle_stdin_input, handle_repl_command,
32
    handle_compile_command, handle_check_command, handle_test_command, handle_complex_command
33
};
34
35
/// Configuration for code formatting
36
#[derive(Debug, Clone)]
37
struct FormatConfig {
38
    #[allow(dead_code)]
39
    line_width: usize,
40
    indent: usize,
41
    use_tabs: bool,
42
}
43
44
impl Default for FormatConfig {
45
0
    fn default() -> Self {
46
0
        Self {
47
0
            line_width: 100,
48
0
            indent: 4,
49
0
            use_tabs: false,
50
0
        }
51
0
    }
52
}
53
54
#[derive(Parser)]
55
#[command(name = "ruchy")]
56
#[command(author, version, about = "The Ruchy programming language", long_about = None)]
57
struct Cli {
58
    /// Evaluate a one-liner expression
59
    #[arg(short = 'e', long = "eval", value_name = "EXPR")]
60
    eval: Option<String>,
61
62
    /// Output format for evaluation results (text, json)
63
    #[arg(long, default_value = "text")]
64
    format: String,
65
66
    /// Enable verbose output
67
    #[arg(short = 'v', long)]
68
    verbose: bool,
69
70
    /// Script file to execute (alternative to subcommands)
71
    file: Option<PathBuf>,
72
73
    #[command(subcommand)]
74
    command: Option<Commands>,
75
}
76
77
#[derive(Subcommand)]
78
enum Commands {
79
    /// Start the interactive REPL
80
    Repl {
81
        /// Record REPL session to a .replay file
82
        #[arg(long, value_name = "FILE")]
83
        record: Option<PathBuf>,
84
    },
85
86
    /// Parse a Ruchy file and show the AST
87
    Parse {
88
        /// The file to parse
89
        file: PathBuf,
90
    },
91
92
    /// Transpile a Ruchy file to Rust
93
    Transpile {
94
        /// The file to transpile
95
        file: PathBuf,
96
97
        /// Output file (defaults to stdout)
98
        #[arg(short, long)]
99
        output: Option<PathBuf>,
100
101
        /// Use minimal codegen for self-hosting (direct Rust mapping, no optimization)
102
        #[arg(long)]
103
        minimal: bool,
104
    },
105
106
    /// Compile and run a Ruchy file
107
    Run {
108
        /// The file to run
109
        file: PathBuf,
110
    },
111
    
112
    /// Compile a Ruchy file to a standalone binary (RUCHY-0801)
113
    Compile {
114
        /// The file to compile
115
        file: PathBuf,
116
        
117
        /// Output binary path
118
        #[arg(short, long, default_value = "a.out")]
119
        output: PathBuf,
120
        
121
        /// Optimization level (0-3, or 's' for size)
122
        #[arg(short = 'O', long, default_value = "2")]
123
        opt_level: String,
124
        
125
        /// Strip debug symbols
126
        #[arg(long)]
127
        strip: bool,
128
        
129
        /// Static linking
130
        #[arg(long)]
131
        static_link: bool,
132
        
133
        /// Target triple (e.g., x86_64-unknown-linux-gnu)
134
        #[arg(long)]
135
        target: Option<String>,
136
    },
137
138
    /// Check syntax without running
139
    Check {
140
        /// The file to check
141
        file: PathBuf,
142
143
        /// Watch for changes and re-check automatically
144
        #[arg(long)]
145
        watch: bool,
146
    },
147
148
    /// Run tests for Ruchy code with optional coverage reporting
149
    Test {
150
        /// The test file or directory to run
151
        path: Option<PathBuf>,
152
153
        /// Watch for changes and re-run tests automatically
154
        #[arg(long)]
155
        watch: bool,
156
157
        /// Show verbose output
158
        #[arg(long)]
159
        verbose: bool,
160
161
        /// Filter tests by name pattern
162
        #[arg(long)]
163
        filter: Option<String>,
164
165
        /// Generate coverage report
166
        #[arg(long)]
167
        coverage: bool,
168
169
        /// Coverage output format (text, html, json)
170
        #[arg(long, default_value = "text")]
171
        coverage_format: String,
172
173
        /// Run tests in parallel
174
        #[arg(long)]
175
        parallel: bool,
176
177
        /// Minimum coverage threshold (fail if below)
178
        #[arg(long)]
179
        threshold: Option<f64>,
180
181
        /// Output format for test results (text, json, junit)
182
        #[arg(long, default_value = "text")]
183
        format: String,
184
    },
185
186
    /// Generate coverage report for Ruchy code
187
    Coverage {
188
        /// The file or directory to analyze  
189
        path: PathBuf,
190
191
        /// Minimum coverage threshold (fail if below)
192
        #[arg(long)]
193
        threshold: Option<f64>,
194
195
        /// Output format for coverage report (text, html, json)
196
        #[arg(long, default_value = "text")]
197
        format: String,
198
199
        /// Show verbose coverage output
200
        #[arg(long)]
201
        verbose: bool,
202
    },
203
204
    /// Show AST for a file (Enhanced for v0.9.12)
205
    Ast {
206
        /// The file to parse
207
        file: PathBuf,
208
209
        /// Output AST in JSON format for tooling integration
210
        #[arg(long)]
211
        json: bool,
212
213
        /// Generate visual AST graph in DOT format
214
        #[arg(long)]
215
        graph: bool,
216
217
        /// Calculate and show complexity metrics
218
        #[arg(long)]
219
        metrics: bool,
220
221
        /// Perform symbol table analysis
222
        #[arg(long)]
223
        symbols: bool,
224
225
        /// Analyze module dependencies
226
        #[arg(long)]
227
        deps: bool,
228
229
        /// Show verbose analysis output
230
        #[arg(long)]
231
        verbose: bool,
232
233
        /// Output file for graph/analysis results
234
        #[arg(long)]
235
        output: Option<PathBuf>,
236
    },
237
238
    /// Formal verification and correctness analysis (RUCHY-0754)
239
    Provability {
240
        /// The file to analyze
241
        file: PathBuf,
242
243
        /// Perform full formal verification
244
        #[arg(long)]
245
        verify: bool,
246
247
        /// Contract verification (pre/post-conditions, invariants)
248
        #[arg(long)]
249
        contracts: bool,
250
251
        /// Loop invariant checking
252
        #[arg(long)]
253
        invariants: bool,
254
255
        /// Termination analysis for loops and recursion
256
        #[arg(long)]
257
        termination: bool,
258
259
        /// Array bounds checking and memory safety
260
        #[arg(long)]
261
        bounds: bool,
262
263
        /// Show verbose verification output
264
        #[arg(long)]
265
        verbose: bool,
266
267
        /// Output file for verification results
268
        #[arg(long)]
269
        output: Option<PathBuf>,
270
    },
271
272
    /// Performance analysis and `BigO` complexity detection (RUCHY-0755)
273
    Runtime {
274
        /// The file to analyze
275
        file: PathBuf,
276
277
        /// Perform detailed execution profiling
278
        #[arg(long)]
279
        profile: bool,
280
281
        /// Automatic `BigO` algorithmic complexity analysis
282
        #[arg(long)]
283
        bigo: bool,
284
285
        /// Benchmark execution with statistical analysis
286
        #[arg(long)]
287
        bench: bool,
288
289
        /// Compare performance between two files
290
        #[arg(long)]
291
        compare: Option<PathBuf>,
292
293
        /// Memory usage and allocation analysis
294
        #[arg(long)]
295
        memory: bool,
296
297
        /// Show verbose performance output
298
        #[arg(long)]
299
        verbose: bool,
300
301
        /// Output file for performance results
302
        #[arg(long)]
303
        output: Option<PathBuf>,
304
    },
305
306
    /// Unified quality scoring (RUCHY-0810)
307
    Score {
308
        /// The file or directory to score
309
        path: PathBuf,
310
311
        /// Analysis depth (shallow/standard/deep)
312
        #[arg(long, default_value = "standard")]
313
        depth: String,
314
315
        /// Fast feedback mode (AST-only, <100ms)
316
        #[arg(long)]
317
        fast: bool,
318
319
        /// Deep analysis for CI (complete, <30s)
320
        #[arg(long)]
321
        deep: bool,
322
323
        /// Watch mode with progressive refinement
324
        #[arg(long)]
325
        watch: bool,
326
327
        /// Explain score changes from baseline
328
        #[arg(long)]
329
        explain: bool,
330
331
        /// Baseline branch/commit for comparison
332
        #[arg(long)]
333
        baseline: Option<String>,
334
335
        /// Minimum score threshold (0.0-1.0)
336
        #[arg(long)]
337
        min: Option<f64>,
338
339
        /// Configuration file
340
        #[arg(long)]
341
        config: Option<PathBuf>,
342
343
        /// Output format (text/json/html)
344
        #[arg(long, default_value = "text")]
345
        format: String,
346
347
        /// Verbose output
348
        #[arg(long)]
349
        verbose: bool,
350
351
        /// Output file for score report
352
        #[arg(long)]
353
        output: Option<PathBuf>,
354
    },
355
356
    /// Quality gate enforcement (RUCHY-0815)
357
    QualityGate {
358
        /// The file or directory to check
359
        path: PathBuf,
360
361
        /// Configuration file (.ruchy/score.toml)
362
        #[arg(long)]
363
        config: Option<PathBuf>,
364
365
        /// Analysis depth (shallow/standard/deep)
366
        #[arg(long, default_value = "standard")]
367
        depth: String,
368
369
        /// Fail fast on first violation
370
        #[arg(long)]
371
        fail_fast: bool,
372
373
        /// Output format (console/json/junit)
374
        #[arg(long, default_value = "console")]
375
        format: String,
376
377
        /// Export CI/CD results
378
        #[arg(long)]
379
        export: Option<PathBuf>,
380
381
        /// Run in CI mode (strict thresholds)
382
        #[arg(long)]
383
        ci: bool,
384
385
        /// Show detailed violation information
386
        #[arg(long)]
387
        verbose: bool,
388
    },
389
390
    /// Format Ruchy source code (Enhanced for v0.9.12)
391
    Fmt {
392
        /// The file to format
393
        file: PathBuf,
394
395
        /// Format all files in project
396
        #[arg(long)]
397
        all: bool,
398
399
        /// Check if files are formatted without modifying them
400
        #[arg(long)]
401
        check: bool,
402
403
        /// Write formatted output to stdout instead of modifying files
404
        #[arg(long)]
405
        stdout: bool,
406
407
        /// Show diff of changes
408
        #[arg(long)]
409
        diff: bool,
410
411
        /// Configuration file for formatting rules
412
        #[arg(long)]
413
        config: Option<PathBuf>,
414
415
        /// Maximum line width for formatting
416
        #[arg(long, default_value = "100")]
417
        line_width: usize,
418
419
        /// Indentation size (spaces)
420
        #[arg(long, default_value = "4")]
421
        indent: usize,
422
423
        /// Use tabs instead of spaces for indentation
424
        #[arg(long)]
425
        use_tabs: bool,
426
    },
427
428
    /// Generate documentation from Ruchy source code
429
    Doc {
430
        /// The file or directory to document
431
        path: PathBuf,
432
433
        /// Output directory for generated documentation
434
        #[arg(long, default_value = "./docs")]
435
        output: PathBuf,
436
437
        /// Documentation format (html, markdown, json)
438
        #[arg(long, default_value = "html")]
439
        format: String,
440
441
        /// Include private items in documentation
442
        #[arg(long)]
443
        private: bool,
444
445
        /// Open documentation in browser after generation
446
        #[arg(long)]
447
        open: bool,
448
449
        /// Generate documentation for all files in project
450
        #[arg(long)]
451
        all: bool,
452
453
        /// Show verbose output
454
        #[arg(long)]
455
        verbose: bool,
456
    },
457
458
    /// Benchmark Ruchy code performance
459
    Bench {
460
        /// The file to benchmark
461
        file: PathBuf,
462
463
        /// Number of iterations to run
464
        #[arg(long, default_value = "100")]
465
        iterations: usize,
466
467
        /// Number of warmup iterations
468
        #[arg(long, default_value = "10")]
469
        warmup: usize,
470
471
        /// Output format (text, json, csv)
472
        #[arg(long, default_value = "text")]
473
        format: String,
474
475
        /// Save results to file
476
        #[arg(long)]
477
        output: Option<PathBuf>,
478
479
        /// Show verbose output including individual runs
480
        #[arg(long)]
481
        verbose: bool,
482
    },
483
484
    /// Lint Ruchy source code for issues and style violations (Enhanced for v0.9.12)
485
    Lint {
486
        /// The file to lint (ignored if --all is used)
487
        file: Option<PathBuf>,
488
489
        /// Lint all files in project
490
        #[arg(long)]
491
        all: bool,
492
493
        /// Auto-fix issues where possible
494
        #[arg(long)]
495
        fix: bool,
496
497
        /// Strict mode with all rules enabled
498
        #[arg(long)]
499
        strict: bool,
500
501
        /// Show additional context for violations
502
        #[arg(long)]
503
        verbose: bool,
504
505
        /// Output format (text, json)
506
        #[arg(long, default_value = "text")]
507
        format: String,
508
509
        /// Specific rule categories to check (comma-separated: unused,style,complexity,safety,performance)
510
        #[arg(long)]
511
        rules: Option<String>,
512
513
        /// Fail on warnings as well as errors
514
        #[arg(long)]
515
        deny_warnings: bool,
516
517
        /// Maximum allowed complexity for functions
518
        #[arg(long, default_value = "10")]
519
        max_complexity: usize,
520
521
        /// Path to custom lint rules configuration file
522
        #[arg(long)]
523
        config: Option<PathBuf>,
524
525
        /// Generate default lint configuration file
526
        #[arg(long)]
527
        init_config: bool,
528
    },
529
530
    /// Add a package dependency
531
    Add {
532
        /// Package name to add
533
        package: String,
534
        /// Specific version to add (default: latest)
535
        #[arg(long)]
536
        version: Option<String>,
537
        /// Add as development dependency
538
        #[arg(long)]
539
        dev: bool,
540
        /// Registry URL to use
541
        #[arg(long, default_value = "https://ruchy.dev/registry")]
542
        registry: String,
543
    },
544
545
    /// Publish a package to the registry
546
    Publish {
547
        /// Registry URL to publish to
548
        #[arg(long, default_value = "https://ruchy.dev/registry")]
549
        registry: String,
550
        /// Package version to publish (reads from Ruchy.toml if not specified)
551
        #[arg(long)]
552
        version: Option<String>,
553
        /// Perform a dry run without actually publishing
554
        #[arg(long)]
555
        dry_run: bool,
556
        /// Allow publishing dirty working directory
557
        #[arg(long)]
558
        allow_dirty: bool,
559
    },
560
    
561
    /// Start MCP server for real-time quality analysis (RUCHY-0811)
562
    Mcp {
563
        /// Server name for MCP identification
564
        #[arg(long, default_value = "ruchy-mcp")]
565
        name: String,
566
        
567
        /// Enable streaming updates
568
        #[arg(long)]
569
        streaming: bool,
570
        
571
        /// Session timeout in seconds
572
        #[arg(long, default_value = "3600")]
573
        timeout: u64,
574
        
575
        /// Minimum quality score threshold
576
        #[arg(long, default_value = "0.8")]
577
        min_score: f64,
578
        
579
        /// Maximum complexity threshold
580
        #[arg(long, default_value = "10")]
581
        max_complexity: u32,
582
        
583
        /// Enable verbose logging
584
        #[arg(short, long)]
585
        verbose: bool,
586
        
587
        /// Configuration file path
588
        #[arg(short, long)]
589
        config: Option<PathBuf>,
590
    },
591
592
    /// Hardware-aware optimization analysis (RUCHY-0816)
593
    Optimize {
594
        /// The file to analyze for optimization opportunities
595
        file: PathBuf,
596
597
        /// Hardware profile to use (detect, intel, amd, arm)
598
        #[arg(long, default_value = "detect")]
599
        hardware: String,
600
601
        /// Analysis depth (quick, standard, deep)
602
        #[arg(long, default_value = "standard")]
603
        depth: String,
604
605
        /// Show cache behavior analysis
606
        #[arg(long)]
607
        cache: bool,
608
609
        /// Show branch prediction analysis
610
        #[arg(long)]
611
        branches: bool,
612
613
        /// Show vectorization opportunities
614
        #[arg(long)]
615
        vectorization: bool,
616
617
        /// Show abstraction cost analysis
618
        #[arg(long)]
619
        abstractions: bool,
620
621
        /// Benchmark hardware characteristics
622
        #[arg(long)]
623
        benchmark: bool,
624
625
        /// Output format (text, json, html)
626
        #[arg(long, default_value = "text")]
627
        format: String,
628
629
        /// Save analysis to file
630
        #[arg(long)]
631
        output: Option<PathBuf>,
632
633
        /// Show verbose optimization details
634
        #[arg(long)]
635
        verbose: bool,
636
637
        /// Minimum impact threshold for recommendations (0.0-1.0)
638
        #[arg(long, default_value = "0.05")]
639
        threshold: f64,
640
    },
641
642
    /// Actor observatory for live system introspection (RUCHY-0817)
643
    #[command(name = "actor:observe")]
644
    ActorObserve {
645
        /// Actor system configuration file
646
        #[arg(long)]
647
        config: Option<PathBuf>,
648
649
        /// Observatory refresh interval in milliseconds
650
        #[arg(long, default_value = "1000")]
651
        refresh_interval: u64,
652
653
        /// Maximum number of message traces to display
654
        #[arg(long, default_value = "50")]
655
        max_traces: usize,
656
657
        /// Maximum number of actors to display
658
        #[arg(long, default_value = "20")]
659
        max_actors: usize,
660
661
        /// Enable deadlock detection
662
        #[arg(long)]
663
        enable_deadlock_detection: bool,
664
665
        /// Deadlock detection interval in milliseconds
666
        #[arg(long, default_value = "1000")]
667
        deadlock_interval: u64,
668
669
        /// Start in a specific view mode (overview, actors, messages, metrics, deadlocks)
670
        #[arg(long, default_value = "overview")]
671
        start_mode: String,
672
673
        /// Disable color output
674
        #[arg(long)]
675
        no_color: bool,
676
677
        /// Output format (interactive, json, text)
678
        #[arg(long, default_value = "interactive")]
679
        format: String,
680
681
        /// Export observations to file
682
        #[arg(long)]
683
        export: Option<PathBuf>,
684
685
        /// Duration to observe in seconds (0 for infinite)
686
        #[arg(long, default_value = "0")]
687
        duration: u64,
688
689
        /// Show verbose output
690
        #[arg(long)]
691
        verbose: bool,
692
693
        /// Add message filter by actor name pattern
694
        #[arg(long)]
695
        filter_actor: Option<String>,
696
697
        /// Add message filter for failed messages only
698
        #[arg(long)]
699
        filter_failed: bool,
700
701
        /// Add message filter for delayed messages (minimum microseconds)
702
        #[arg(long)]
703
        filter_slow: Option<u64>,
704
    },
705
706
    /// Dataflow debugger for `DataFrame` pipeline debugging (RUCHY-0818)
707
    #[command(name = "dataflow:debug")]
708
    DataflowDebug {
709
        /// Pipeline configuration file
710
        #[arg(long)]
711
        config: Option<PathBuf>,
712
        
713
        /// Maximum rows to materialize per stage
714
        #[arg(long, default_value = "1000")]
715
        max_rows: usize,
716
        
717
        /// Auto-materialize data at each stage
718
        #[arg(long)]
719
        auto_materialize: bool,
720
        
721
        /// Enable performance profiling
722
        #[arg(long, default_value = "true")]
723
        enable_profiling: bool,
724
        
725
        /// Stage execution timeout in milliseconds
726
        #[arg(long, default_value = "30000")]
727
        timeout: u64,
728
        
729
        /// Enable memory tracking
730
        #[arg(long)]
731
        track_memory: bool,
732
        
733
        /// Compute diffs between stages
734
        #[arg(long)]
735
        compute_diffs: bool,
736
        
737
        /// Sample rate for large datasets (0.0-1.0)
738
        #[arg(long, default_value = "1.0")]
739
        sample_rate: f64,
740
        
741
        /// UI refresh interval in milliseconds
742
        #[arg(long, default_value = "1000")]
743
        refresh_interval: u64,
744
        
745
        /// Disable color output
746
        #[arg(long)]
747
        no_color: bool,
748
        
749
        /// Output format (interactive, json, text)
750
        #[arg(long, default_value = "interactive")]
751
        format: String,
752
        
753
        /// Export debug data to file
754
        #[arg(long)]
755
        export: Option<PathBuf>,
756
        
757
        /// Show verbose debugging output
758
        #[arg(long)]
759
        verbose: bool,
760
        
761
        /// Add breakpoint at stage (can be used multiple times)
762
        #[arg(long)]
763
        breakpoint: Vec<String>,
764
        
765
        /// Start mode (overview, stages, data, metrics, history)
766
        #[arg(long, default_value = "overview")]
767
        start_mode: String,
768
    },
769
770
    /// WebAssembly component toolkit (RUCHY-0819)
771
    Wasm {
772
        /// The source file to compile to WASM
773
        file: PathBuf,
774
        
775
        /// Output file for the WASM component
776
        #[arg(short, long)]
777
        output: Option<PathBuf>,
778
        
779
        /// Target platform (wasm32, wasi, browser, nodejs, cloudflare-workers)
780
        #[arg(long, default_value = "wasm32")]
781
        target: String,
782
        
783
        /// Generate WIT interface definition
784
        #[arg(long)]
785
        wit: bool,
786
        
787
        /// Deploy to target platform
788
        #[arg(long)]
789
        deploy: bool,
790
        
791
        /// Deployment target (cloudflare, fastly, aws-lambda, vercel, deno)
792
        #[arg(long)]
793
        deploy_target: Option<String>,
794
        
795
        /// Analyze portability across platforms
796
        #[arg(long)]
797
        portability: bool,
798
        
799
        /// Optimization level (none, O1, O2, O3, Os, Oz)
800
        #[arg(long, default_value = "O2")]
801
        opt_level: String,
802
        
803
        /// Include debug information
804
        #[arg(long)]
805
        debug: bool,
806
        
807
        /// Enable SIMD instructions
808
        #[arg(long)]
809
        simd: bool,
810
        
811
        /// Enable threads and atomics
812
        #[arg(long)]
813
        threads: bool,
814
        
815
        /// Enable component model
816
        #[arg(long, default_value = "true")]
817
        component_model: bool,
818
        
819
        /// Component name
820
        #[arg(long)]
821
        name: Option<String>,
822
        
823
        /// Component version
824
        #[arg(long, default_value = "0.1.0")]
825
        version: String,
826
        
827
        /// Show verbose output
828
        #[arg(long)]
829
        verbose: bool,
830
    },
831
    
832
    /// Interactive theorem prover (RUCHY-0820)
833
    Prove {
834
        /// The file to verify (optional, starts REPL if not provided)
835
        file: Option<PathBuf>,
836
        
837
        /// SMT backend (z3, cvc5, yices2)
838
        #[arg(long, default_value = "z3")]
839
        backend: String,
840
        
841
        /// Enable ML-powered tactic suggestions
842
        #[arg(long)]
843
        ml_suggestions: bool,
844
        
845
        /// Timeout for SMT queries in milliseconds
846
        #[arg(long, default_value = "5000")]
847
        timeout: u64,
848
        
849
        /// Load proof script
850
        #[arg(long)]
851
        script: Option<PathBuf>,
852
        
853
        /// Export proof to file
854
        #[arg(long)]
855
        export: Option<PathBuf>,
856
        
857
        /// Non-interactive mode (check proofs only)
858
        #[arg(long)]
859
        check: bool,
860
        
861
        /// Generate counterexamples for failed proofs
862
        #[arg(long)]
863
        counterexample: bool,
864
        
865
        /// Show verbose proof output
866
        #[arg(long)]
867
        verbose: bool,
868
        
869
        /// Output format (text, json, coq, lean)
870
        #[arg(long, default_value = "text")]
871
        format: String,
872
    },
873
874
    /// Convert REPL replay files to regression tests
875
    ReplayToTests {
876
        /// Input replay file or directory containing .replay files
877
        input: PathBuf,
878
879
        /// Output test file (defaults to `tests/generated_from_replays.rs`)
880
        #[arg(short, long)]
881
        output: Option<PathBuf>,
882
883
        /// Include property tests for invariants
884
        #[arg(long)]
885
        property_tests: bool,
886
887
        /// Include performance benchmarks
888
        #[arg(long)]
889
        benchmarks: bool,
890
891
        /// Test timeout in milliseconds
892
        #[arg(long, default_value = "5000")]
893
        timeout: u64,
894
    },
895
}
896
897
0
fn main() -> Result<()> {
898
0
    let cli = Cli::parse();
899
900
    // Try to handle direct evaluation first
901
0
    if let Some(result) = try_handle_direct_evaluation(&cli) {
902
0
        return result;
903
0
    }
904
905
    // Try to handle stdin input
906
0
    if let Some(result) = try_handle_stdin(cli.command.as_ref())? {
907
0
        return result;
908
0
    }
909
910
    // Handle subcommands
911
0
    handle_command_dispatch(cli.command, cli.verbose)
912
0
}
913
914
/// Handle direct evaluation via -e flag or file argument (complexity: 4)
915
0
fn try_handle_direct_evaluation(cli: &Cli) -> Option<Result<()>> {
916
    // Handle one-liner evaluation with -e flag
917
0
    if let Some(expr) = &cli.eval {
918
0
        return Some(handle_eval_command(expr, cli.verbose, &cli.format));
919
0
    }
920
921
    // Handle script file execution (without subcommand)
922
0
    if let Some(file) = &cli.file {
923
0
        return Some(handle_file_execution(file));
924
0
    }
925
926
0
    None
927
0
}
928
929
/// Handle stdin input if present (complexity: 5)
930
0
fn try_handle_stdin(command: Option<&Commands>) -> Result<Option<Result<()>>> {
931
    // Check if stdin has input (piped mode) - but only when no command is specified
932
0
    if !io::stdin().is_terminal() && command.is_none() {
933
0
        let mut input = String::new();
934
0
        io::stdin().read_to_string(&mut input)?;
935
936
0
        if !input.trim().is_empty() {
937
0
            return Ok(Some(handle_stdin_input(&input)));
938
0
        }
939
0
    }
940
    
941
0
    Ok(None)
942
0
}
943
944
/// Dispatch commands to appropriate handlers (complexity: 6)
945
0
fn handle_command_dispatch(command: Option<Commands>, verbose: bool) -> Result<()> {
946
0
    match command {
947
0
        Some(Commands::Repl { record }) => handle_repl_command(record),
948
0
        None => handle_repl_command(None),
949
0
        Some(Commands::Parse { file }) => handle_parse_command(&file, verbose),
950
0
        Some(Commands::Transpile { file, output, minimal }) => {
951
0
            handle_transpile_command(&file, output.as_deref(), minimal, verbose)
952
        }
953
0
        Some(Commands::Run { file }) => handle_run_command(&file, verbose),
954
0
        Some(Commands::Compile { file, output, opt_level, strip, static_link, target }) => {
955
0
            handle_compile_command(&file, output, opt_level, strip, static_link, target)
956
        }
957
0
        Some(Commands::Check { file, watch }) => handle_check_command(&file, watch),
958
0
        Some(Commands::Test { path, watch, verbose, filter, coverage, coverage_format, parallel, threshold, format }) => {
959
0
            handle_test_dispatch(path, watch, verbose, filter.as_ref(), coverage, &coverage_format, parallel, threshold, &format)
960
        }
961
0
        Some(command) => handle_advanced_command(command),
962
    }
963
0
}
964
965
/// Handle test command with all its parameters (complexity: 3)
966
0
fn handle_test_dispatch(
967
0
    path: Option<PathBuf>,
968
0
    watch: bool,
969
0
    verbose: bool,
970
0
    filter: Option<&String>,
971
0
    coverage: bool,
972
0
    coverage_format: &str,
973
0
    parallel: bool,
974
0
    threshold: Option<f64>,
975
0
    format: &str,
976
0
) -> Result<()> {
977
0
    handle_test_command(
978
0
        path,
979
0
        watch,
980
0
        verbose,
981
0
        filter.map(String::as_str),
982
0
        coverage,
983
0
        coverage_format,
984
0
        usize::from(parallel),
985
0
        threshold.unwrap_or(0.0),
986
0
        format,
987
    )
988
0
}
989
990
0
fn handle_advanced_command(command: Commands) -> Result<()> {
991
    // Delegate to the existing handle_complex_command from cli module
992
0
    handle_complex_command(command)
993
0
}
994
995
0
fn run_file(file: &Path) -> Result<()> {
996
0
    let source = fs::read_to_string(file)?;
997
998
    // Use REPL to evaluate the file
999
0
    let mut repl = Repl::new()?;
1000
0
    match repl.eval(&source) {
1001
0
        Ok(result) => {
1002
            // Only print non-unit results
1003
0
            if result != "Unit" && result != "()" {
1004
0
                println!("{result}");
1005
0
            }
1006
0
            Ok(())
1007
        }
1008
0
        Err(e) => {
1009
0
            eprintln!("Error: {e}");
1010
0
            std::process::exit(1);
1011
        }
1012
    }
1013
0
}
1014
1015
/// Check syntax of a file
1016
0
fn check_syntax(file: &Path) -> Result<()> {
1017
    use colored::Colorize;
1018
0
    let source = fs::read_to_string(file)?;
1019
0
    let mut parser = RuchyParser::new(&source);
1020
0
    match parser.parse() {
1021
        Ok(_) => {
1022
0
            println!("{}", "✓ Syntax is valid".green());
1023
0
            Ok(())
1024
        }
1025
0
        Err(e) => {
1026
0
            eprintln!("{}", format!("✗ Syntax error: {e}").red());
1027
0
            std::process::exit(1);
1028
        }
1029
    }
1030
0
}
1031