1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
//! Command-line argument parser for the Carlo language.
use std::{
env::args,
path::PathBuf,
};
use crate::Error;
#[derive(Clone, Copy, PartialEq, Eq)]
/// Subcommands for the Carlo language executable.
pub enum Subcommand {
/// Executes a REPL
Repl,
/// Executes a source file
Run,
/// Converts a source file into LaTeX
Latex,
/// Displays a help menu
Help,
/// Displays the version
Version,
}
/// Converts a string into a subcommand.
impl From<&str> for Subcommand {
fn from(input: &str) -> Self {
use Subcommand::*;
match input {
"repl" => Repl,
"run" => Run,
"latex" => Latex,
"help" => Help,
"version" => Version,
_ => Error::UnrecognizedSubcommand (input).throw(),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
/// Flags for the Carlo language executable.
pub enum Flag {
/// Runs the Carlo language parser in debug mode
Debug,
/// Runs the Carlo language help menu in interactive mode
Interactive,
}
/// Converts a string into a flag.
impl From<&str> for Flag {
fn from(input: &str) -> Self {
use Flag::*;
match input {
"debug" => Debug,
"interactive" => Interactive,
_ => Error::UnrecognizedFlag (input).throw(),
}
}
}
/// Converts a character into a flag.
impl From<char> for Flag {
fn from(input: char) -> Self {
use Flag::*;
match input {
'd' => Debug,
'i' => Interactive,
_ => Error::UnrecognizedFlag (input).throw(),
}
}
}
/// Command-line arguments for the Carlo language executable.
pub struct CliArgs {
/// Executable subcommand
pub subcommand: Subcommand,
/// Argument to subcommand
pub argument: Option<String>,
/// Input file
pub inputfile: Option<PathBuf>,
/// Flags
pub flags: Vec<Flag>,
}
impl CliArgs {
/// Parses command-line arguments.
pub fn parse() -> Self {
let args = args().collect::<Vec<String>>();
// Parse subcommand
let subcommand = if args.len() > 1 {
args[1].as_str().into()
} else {
Subcommand::Repl
};
let mut argument: Option<String> = None;
let mut inputfile: Option<PathBuf> = None;
// Parse argument or input file
if subcommand == Subcommand::Help && args.len() > 2 && !args[2].starts_with("-") {
argument = Some (args[2].to_owned());
} else if subcommand != Subcommand::Help && args.len() > 2 && !args[2].starts_with("-") {
inputfile = Some (args[2].as_str().into());
}
// Parse flags
let mut flags = Vec::new();
let mut i = if let Some (_) = &inputfile {
3
} else if let Some(_) = &argument {
3
} else {
2
};
while i < args.len() {
let arg = &args[i];
if arg.starts_with("--") {
flags.push(arg[2..].into());
} else if arg.starts_with("-") {
for c in arg[1..].chars() {
flags.push(c.into());
}
} else {
Error::UnrecognizedArgument (arg).throw();
}
i += 1;
}
Self {
subcommand,
argument,
inputfile,
flags,
}
}
/// Check if a specific flag is contained in these arguments.
pub fn contains(&self, flag: Flag) -> bool {
for f in &self.flags {
if *f == flag {
return true;
}
}
return false;
}
}