72 lines
2.0 KiB
Rust
72 lines
2.0 KiB
Rust
//! Command line interface for the language binary.
|
|
|
|
use std::ffi::OsString;
|
|
use std::path::PathBuf;
|
|
|
|
use pico_args::Arguments;
|
|
use thiserror::Error;
|
|
|
|
/// Usage help text.
|
|
pub const USAGE: &str = "
|
|
USAGE:
|
|
mul [-h|--help] (parse <FILE> | evaluate <FILE> | repl)
|
|
|
|
FLAGS:
|
|
-h, --help Prints help information (this text)
|
|
|
|
COMMANDS:
|
|
parse <FILE> Parse the given file and print a serialized AST to stdout
|
|
evaluate, eval <FILE> Evaluate the given file
|
|
repl Start the Read-Evaluate-Print-Loop
|
|
";
|
|
|
|
/// Errors that may occur during command line parsing.
|
|
#[derive(Debug, Error)]
|
|
pub enum Error {
|
|
#[error("Problem while parsing arguments, {0}")]
|
|
ArgsError(#[from] pico_args::Error),
|
|
#[error("Invalid command '{0}'\n{USAGE}")]
|
|
InvalidCommand(String),
|
|
#[error("Unrecognized arguments {0:?}\n{USAGE}")]
|
|
UnrecognizedArguments(Vec<OsString>),
|
|
}
|
|
|
|
/// Possible top level commands.
|
|
pub enum Command {
|
|
Parse { path: PathBuf },
|
|
Run { path: PathBuf },
|
|
Repl,
|
|
}
|
|
|
|
impl Command {
|
|
/// Parse the command line from the current environment.
|
|
pub fn from_environment() -> Result<Option<Self>, Error> {
|
|
Self::from_arguments(Arguments::from_env())
|
|
}
|
|
|
|
/// Parse a command from raw arguments.
|
|
pub fn from_arguments(mut args: Arguments) -> Result<Option<Self>, Error> {
|
|
if args.contains(["-h", "--help"]) {
|
|
return Ok(None);
|
|
}
|
|
let cmd = match args.subcommand()?.as_deref() {
|
|
Some("parse") => {
|
|
let path = args.free_from_str()?;
|
|
Command::Parse { path }
|
|
}
|
|
Some("run") => {
|
|
let path = args.free_from_str()?;
|
|
Command::Run { path }
|
|
}
|
|
Some("repl") | None => Command::Repl,
|
|
Some(cmd) => return Err(Error::InvalidCommand(cmd.to_string())),
|
|
};
|
|
let remaining = args.finish();
|
|
if remaining.is_empty() {
|
|
Ok(Some(cmd))
|
|
} else {
|
|
Err(Error::UnrecognizedArguments(remaining))
|
|
}
|
|
}
|
|
}
|