Skip to main content

avm_rs/cli/
mod.rs

1//! Command-line interface for the Rust AVM
2
3use clap::{Command, Parser, Subcommand};
4use std::path::PathBuf;
5
6mod commands;
7pub use commands::*;
8
9/// Rust AVM - Algorand Virtual Machine implementation in Rust
10#[derive(Parser)]
11#[command(
12    name = "avm-rs",
13    version = env!("CARGO_PKG_VERSION"),
14    about = "Algorand Virtual Machine (AVM) implementation in Rust",
15    long_about = "A complete implementation of the Algorand Virtual Machine (AVM) that can execute TEAL smart contracts. Supports assembly, disassembly, execution, validation, and debugging of TEAL programs."
16)]
17pub struct Cli {
18    /// Global options
19    #[command(flatten)]
20    pub global: GlobalOptions,
21
22    /// Subcommands
23    #[command(subcommand)]
24    pub command: Commands,
25}
26
27/// Global options available for all commands
28#[derive(Parser)]
29pub struct GlobalOptions {
30    /// Enable verbose output
31    #[arg(short = 'v', long = "verbose", global = true)]
32    pub verbose: bool,
33
34    /// Suppress all output except errors
35    #[arg(short = 'q', long = "quiet", global = true)]
36    pub quiet: bool,
37
38    /// Output format (text, json)
39    #[arg(
40        long = "output-style",
41        value_enum,
42        default_value = "text",
43        global = true
44    )]
45    pub format: OutputFormat,
46
47    /// Enable colored output (auto, always, never)
48    #[arg(long = "color", value_enum, default_value = "auto", global = true)]
49    pub color: ColorChoice,
50}
51
52/// Output format options
53#[derive(clap::ValueEnum, Clone, Debug)]
54pub enum OutputFormat {
55    Text,
56    Json,
57}
58
59/// Color output options
60#[derive(clap::ValueEnum, Clone, Debug)]
61pub enum ColorChoice {
62    Auto,
63    Always,
64    Never,
65}
66
67/// Tracing level options
68#[cfg(feature = "tracing")]
69#[derive(clap::ValueEnum, Clone, Debug)]
70pub enum TracingLevel {
71    Trace,
72    Debug,
73    Info,
74    Warn,
75    Error,
76}
77
78/// Available CLI commands
79#[derive(Subcommand)]
80pub enum Commands {
81    /// Execute TEAL programs
82    #[command(alias = "run")]
83    Execute(ExecuteCommand),
84
85    /// Assemble TEAL source to bytecode
86    #[command(aliases = ["asm", "compile"])]
87    Assemble(AssembleCommand),
88
89    /// Validate TEAL programs
90    #[command(alias = "check")]
91    Validate(ValidateCommand),
92}
93
94/// Execute command for running TEAL programs
95#[derive(Parser)]
96pub struct ExecuteCommand {
97    /// Input source (file path, hex bytecode, or inline TEAL)
98    #[arg(value_name = "INPUT")]
99    pub input: String,
100
101    /// Input type (auto-detect, file, bytecode, inline)
102    #[arg(short = 't', long = "type", value_enum, default_value = "auto")]
103    pub input_type: InputType,
104
105    /// TEAL version to use
106    #[arg(short = 'V', long = "version", value_parser = clap::value_parser!(u8).range(1..=11))]
107    pub version: Option<u8>,
108
109    /// Execution mode (signature or application)
110    #[arg(short = 'm', long = "mode", value_enum, default_value = "signature")]
111    pub mode: ExecutionMode,
112
113    /// Maximum cost budget
114    #[arg(short = 'b', long = "budget", default_value = "100000")]
115    pub budget: u64,
116
117    /// Step through execution (debug mode)
118    #[arg(short = 's', long = "step")]
119    pub step: bool,
120
121    /// Mock ledger data from JSON file
122    #[arg(short = 'l', long = "ledger")]
123    pub ledger: Option<PathBuf>,
124
125    /// Transaction data from JSON file
126    #[arg(short = 'x', long = "txn")]
127    pub transaction: Option<PathBuf>,
128
129    /// Arguments to pass to the program
130    #[arg(short = 'a', long = "arg")]
131    pub args: Vec<String>,
132
133    /// Tracing level (trace, debug, info, warn, error) - enables tracing when specified
134    #[cfg(feature = "tracing")]
135    #[arg(long = "trace-level", value_enum)]
136    pub trace_level: Option<TracingLevel>,
137
138    /// Enable opcode-level tracing
139    #[cfg(feature = "tracing")]
140    #[arg(long = "trace-opcodes")]
141    pub trace_opcodes: bool,
142
143    /// Enable stack state tracing
144    #[cfg(feature = "tracing")]
145    #[arg(long = "trace-stack")]
146    pub trace_stack: bool,
147}
148
149/// Assemble command for converting TEAL to bytecode
150#[derive(Parser)]
151pub struct AssembleCommand {
152    /// Input TEAL file
153    #[arg(value_name = "INPUT")]
154    pub input: PathBuf,
155
156    /// Output bytecode file
157    #[arg(short = 'o', long = "output")]
158    pub output: Option<PathBuf>,
159
160    /// Output format (hex, base64, binary)
161    #[arg(short = 'f', long = "output-format", value_enum, default_value = "hex")]
162    pub output_format: BytecodeFormat,
163
164    /// Optimize the bytecode
165    #[arg(long = "optimize")]
166    pub optimize: bool,
167
168    /// Show assembly statistics
169    #[arg(long = "stats")]
170    pub stats: bool,
171}
172
173/// Disassemble command for converting bytecode to TEAL
174#[derive(Parser)]
175pub struct DisassembleCommand {
176    /// Input bytecode (file path or hex string)
177    #[arg(value_name = "INPUT")]
178    pub input: String,
179
180    /// Input format (auto, hex, base64, binary)
181    #[arg(short = 'i', long = "input-format", value_enum, default_value = "auto")]
182    pub input_format: BytecodeFormat,
183
184    /// Output TEAL file
185    #[arg(short = 'o', long = "output")]
186    pub output: Option<PathBuf>,
187
188    /// Include comments in output
189    #[arg(short = 'c', long = "comments")]
190    pub comments: bool,
191
192    /// Show program analysis
193    #[arg(long = "analyze")]
194    pub analyze: bool,
195}
196
197/// Validate command for checking TEAL programs
198#[derive(Parser)]
199pub struct ValidateCommand {
200    /// Input files to validate
201    #[arg(value_name = "FILES")]
202    pub files: Vec<PathBuf>,
203
204    /// TEAL version to validate against
205    #[arg(short = 'V', long = "version", value_parser = clap::value_parser!(u8).range(1..=11))]
206    pub version: Option<u8>,
207
208    /// Execution mode to validate for
209    #[arg(short = 'm', long = "mode", value_enum)]
210    pub mode: Option<ExecutionMode>,
211
212    /// Strict validation (fail on warnings)
213    #[arg(short = 's', long = "strict")]
214    pub strict: bool,
215
216    /// Show detailed analysis
217    #[arg(long = "detailed")]
218    pub detailed: bool,
219}
220
221/// Examples command for running built-in examples
222#[derive(Parser)]
223pub struct ExamplesCommand {
224    /// List available examples
225    #[arg(short = 'l', long = "list")]
226    pub list: bool,
227
228    /// Example to run
229    #[arg(value_name = "EXAMPLE")]
230    pub example: Option<String>,
231
232    /// Show example source code
233    #[arg(short = 's', long = "show")]
234    pub show: bool,
235
236    /// Execute the example
237    #[arg(short = 'r', long = "run")]
238    pub run: bool,
239}
240
241/// Info command for showing AVM information
242#[derive(Parser)]
243pub struct InfoCommand {
244    /// Show supported TEAL versions
245    #[arg(long = "versions")]
246    pub versions: bool,
247
248    /// Show available opcodes
249    #[arg(long = "opcodes")]
250    pub opcodes: bool,
251
252    /// Filter opcodes by version
253    #[arg(short = 'V', long = "version", value_parser = clap::value_parser!(u8).range(1..=11))]
254    pub version: Option<u8>,
255
256    /// Show opcode details
257    #[arg(short = 'd', long = "details")]
258    pub details: bool,
259
260    /// Show system information
261    #[arg(long = "system")]
262    pub system: bool,
263}
264
265/// REPL command for interactive mode
266#[derive(Parser)]
267pub struct ReplCommand {
268    /// TEAL version for the session
269    #[arg(short = 'V', long = "version", value_parser = clap::value_parser!(u8).range(1..=11), default_value = "11")]
270    pub version: u8,
271
272    /// Execution mode
273    #[arg(short = 'm', long = "mode", value_enum, default_value = "signature")]
274    pub mode: ExecutionMode,
275
276    /// Load initial script
277    #[arg(short = 'l', long = "load")]
278    pub load: Option<PathBuf>,
279}
280
281/// Input type enumeration
282#[derive(clap::ValueEnum, Clone, Debug)]
283pub enum InputType {
284    /// Auto-detect input type
285    Auto,
286    /// File path
287    File,
288    /// Hex bytecode string
289    Bytecode,
290    /// Inline TEAL source
291    Inline,
292}
293
294/// Execution mode enumeration
295#[derive(clap::ValueEnum, Clone, Debug)]
296pub enum ExecutionMode {
297    /// Signature verification mode (stateless)
298    Signature,
299    /// Application mode (stateful)
300    Application,
301}
302
303/// Bytecode format enumeration
304#[derive(clap::ValueEnum, Clone, Debug)]
305pub enum BytecodeFormat {
306    /// Auto-detect format
307    Auto,
308    /// Hexadecimal string
309    Hex,
310    /// Base64 encoding
311    Base64,
312    /// Raw binary
313    Binary,
314}
315
316impl Cli {
317    /// Parse CLI arguments
318    pub fn parse_args() -> Self {
319        Self::parse()
320    }
321
322    /// Create CLI command structure (for building help, completions, etc.)
323    pub fn command() -> Command {
324        <Self as clap::CommandFactory>::command()
325    }
326}
327
328/// Initialize and run the CLI application
329pub fn run() -> anyhow::Result<()> {
330    let cli = Cli::parse_args();
331
332    // Handle global options
333    setup_logging(&cli.global)?;
334    setup_colors(&cli.global)?;
335
336    // Dispatch to appropriate command handler
337    match cli.command {
338        Commands::Execute(cmd) => commands::execute::handle(cmd, &cli.global),
339        Commands::Assemble(cmd) => commands::assemble::handle(cmd, &cli.global),
340        Commands::Validate(cmd) => commands::validate::handle(cmd, &cli.global),
341    }
342}
343
344/// Setup logging based on global options
345fn setup_logging(_global: &GlobalOptions) -> anyhow::Result<()> {
346    // TODO: Implement proper logging setup
347    Ok(())
348}
349
350/// Setup color output based on global options
351fn setup_colors(_global: &GlobalOptions) -> anyhow::Result<()> {
352    // TODO: Implement color setup
353    Ok(())
354}