/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 | | |