1use clap::{Command, Parser, Subcommand};
4use std::path::PathBuf;
5
6mod commands;
7pub use commands::*;
8
9#[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 #[command(flatten)]
20 pub global: GlobalOptions,
21
22 #[command(subcommand)]
24 pub command: Commands,
25}
26
27#[derive(Parser)]
29pub struct GlobalOptions {
30 #[arg(short = 'v', long = "verbose", global = true)]
32 pub verbose: bool,
33
34 #[arg(short = 'q', long = "quiet", global = true)]
36 pub quiet: bool,
37
38 #[arg(
40 long = "output-style",
41 value_enum,
42 default_value = "text",
43 global = true
44 )]
45 pub format: OutputFormat,
46
47 #[arg(long = "color", value_enum, default_value = "auto", global = true)]
49 pub color: ColorChoice,
50}
51
52#[derive(clap::ValueEnum, Clone, Debug)]
54pub enum OutputFormat {
55 Text,
56 Json,
57}
58
59#[derive(clap::ValueEnum, Clone, Debug)]
61pub enum ColorChoice {
62 Auto,
63 Always,
64 Never,
65}
66
67#[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#[derive(Subcommand)]
80pub enum Commands {
81 #[command(alias = "run")]
83 Execute(ExecuteCommand),
84
85 #[command(aliases = ["asm", "compile"])]
87 Assemble(AssembleCommand),
88
89 #[command(alias = "check")]
91 Validate(ValidateCommand),
92}
93
94#[derive(Parser)]
96pub struct ExecuteCommand {
97 #[arg(value_name = "INPUT")]
99 pub input: String,
100
101 #[arg(short = 't', long = "type", value_enum, default_value = "auto")]
103 pub input_type: InputType,
104
105 #[arg(short = 'V', long = "version", value_parser = clap::value_parser!(u8).range(1..=11))]
107 pub version: Option<u8>,
108
109 #[arg(short = 'm', long = "mode", value_enum, default_value = "signature")]
111 pub mode: ExecutionMode,
112
113 #[arg(short = 'b', long = "budget", default_value = "100000")]
115 pub budget: u64,
116
117 #[arg(short = 's', long = "step")]
119 pub step: bool,
120
121 #[arg(short = 'l', long = "ledger")]
123 pub ledger: Option<PathBuf>,
124
125 #[arg(short = 'x', long = "txn")]
127 pub transaction: Option<PathBuf>,
128
129 #[arg(short = 'a', long = "arg")]
131 pub args: Vec<String>,
132
133 #[cfg(feature = "tracing")]
135 #[arg(long = "trace-level", value_enum)]
136 pub trace_level: Option<TracingLevel>,
137
138 #[cfg(feature = "tracing")]
140 #[arg(long = "trace-opcodes")]
141 pub trace_opcodes: bool,
142
143 #[cfg(feature = "tracing")]
145 #[arg(long = "trace-stack")]
146 pub trace_stack: bool,
147}
148
149#[derive(Parser)]
151pub struct AssembleCommand {
152 #[arg(value_name = "INPUT")]
154 pub input: PathBuf,
155
156 #[arg(short = 'o', long = "output")]
158 pub output: Option<PathBuf>,
159
160 #[arg(short = 'f', long = "output-format", value_enum, default_value = "hex")]
162 pub output_format: BytecodeFormat,
163
164 #[arg(long = "optimize")]
166 pub optimize: bool,
167
168 #[arg(long = "stats")]
170 pub stats: bool,
171}
172
173#[derive(Parser)]
175pub struct DisassembleCommand {
176 #[arg(value_name = "INPUT")]
178 pub input: String,
179
180 #[arg(short = 'i', long = "input-format", value_enum, default_value = "auto")]
182 pub input_format: BytecodeFormat,
183
184 #[arg(short = 'o', long = "output")]
186 pub output: Option<PathBuf>,
187
188 #[arg(short = 'c', long = "comments")]
190 pub comments: bool,
191
192 #[arg(long = "analyze")]
194 pub analyze: bool,
195}
196
197#[derive(Parser)]
199pub struct ValidateCommand {
200 #[arg(value_name = "FILES")]
202 pub files: Vec<PathBuf>,
203
204 #[arg(short = 'V', long = "version", value_parser = clap::value_parser!(u8).range(1..=11))]
206 pub version: Option<u8>,
207
208 #[arg(short = 'm', long = "mode", value_enum)]
210 pub mode: Option<ExecutionMode>,
211
212 #[arg(short = 's', long = "strict")]
214 pub strict: bool,
215
216 #[arg(long = "detailed")]
218 pub detailed: bool,
219}
220
221#[derive(Parser)]
223pub struct ExamplesCommand {
224 #[arg(short = 'l', long = "list")]
226 pub list: bool,
227
228 #[arg(value_name = "EXAMPLE")]
230 pub example: Option<String>,
231
232 #[arg(short = 's', long = "show")]
234 pub show: bool,
235
236 #[arg(short = 'r', long = "run")]
238 pub run: bool,
239}
240
241#[derive(Parser)]
243pub struct InfoCommand {
244 #[arg(long = "versions")]
246 pub versions: bool,
247
248 #[arg(long = "opcodes")]
250 pub opcodes: bool,
251
252 #[arg(short = 'V', long = "version", value_parser = clap::value_parser!(u8).range(1..=11))]
254 pub version: Option<u8>,
255
256 #[arg(short = 'd', long = "details")]
258 pub details: bool,
259
260 #[arg(long = "system")]
262 pub system: bool,
263}
264
265#[derive(Parser)]
267pub struct ReplCommand {
268 #[arg(short = 'V', long = "version", value_parser = clap::value_parser!(u8).range(1..=11), default_value = "11")]
270 pub version: u8,
271
272 #[arg(short = 'm', long = "mode", value_enum, default_value = "signature")]
274 pub mode: ExecutionMode,
275
276 #[arg(short = 'l', long = "load")]
278 pub load: Option<PathBuf>,
279}
280
281#[derive(clap::ValueEnum, Clone, Debug)]
283pub enum InputType {
284 Auto,
286 File,
288 Bytecode,
290 Inline,
292}
293
294#[derive(clap::ValueEnum, Clone, Debug)]
296pub enum ExecutionMode {
297 Signature,
299 Application,
301}
302
303#[derive(clap::ValueEnum, Clone, Debug)]
305pub enum BytecodeFormat {
306 Auto,
308 Hex,
310 Base64,
312 Binary,
314}
315
316impl Cli {
317 pub fn parse_args() -> Self {
319 Self::parse()
320 }
321
322 pub fn command() -> Command {
324 <Self as clap::CommandFactory>::command()
325 }
326}
327
328pub fn run() -> anyhow::Result<()> {
330 let cli = Cli::parse_args();
331
332 setup_logging(&cli.global)?;
334 setup_colors(&cli.global)?;
335
336 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
344fn setup_logging(_global: &GlobalOptions) -> anyhow::Result<()> {
346 Ok(())
348}
349
350fn setup_colors(_global: &GlobalOptions) -> anyhow::Result<()> {
352 Ok(())
354}