224 lines
5.4 KiB
Rust
224 lines
5.4 KiB
Rust
use std::ops::Deref;
|
|
use std::path::PathBuf;
|
|
|
|
use clap::{CommandFactory, Parser, Subcommand};
|
|
|
|
pub struct Args {
|
|
inner: ArgsInner,
|
|
}
|
|
|
|
#[derive(Parser)]
|
|
pub struct ArgsInner {
|
|
#[clap(subcommand)]
|
|
pub command: Command,
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
pub enum Command {
|
|
Lex {
|
|
input: PathBuf,
|
|
output_tokens: PathBuf,
|
|
output_symbols: PathBuf,
|
|
},
|
|
Syn {
|
|
input: PathBuf,
|
|
output_tree: PathBuf,
|
|
},
|
|
Sem {
|
|
input: PathBuf,
|
|
output_tree: PathBuf,
|
|
},
|
|
Gen {
|
|
mode: GenMode,
|
|
#[clap(short, long, default_value_t = false)]
|
|
optimize: bool,
|
|
input: PathBuf,
|
|
output: PathBuf,
|
|
output_symbols: PathBuf,
|
|
},
|
|
Com {
|
|
#[clap(short, long, default_value_t = false)]
|
|
optimize: bool,
|
|
input: PathBuf,
|
|
output: PathBuf,
|
|
},
|
|
Int {
|
|
input: PathBuf,
|
|
},
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, clap::ValueEnum)]
|
|
pub enum GenMode {
|
|
#[clap(name = "intermediate", alias = "i")]
|
|
Intermediate,
|
|
#[clap(name = "postfix", alias = "p")]
|
|
Postfix,
|
|
}
|
|
|
|
impl Args {
|
|
pub fn parse() -> Self {
|
|
let inner = match validate_inner(ArgsInner::parse()) {
|
|
Ok(args) => args,
|
|
Err(err) => {
|
|
let mut command = ArgsInner::command();
|
|
err.format(&mut command).exit();
|
|
},
|
|
};
|
|
|
|
Self { inner }
|
|
}
|
|
}
|
|
|
|
impl Deref for Args {
|
|
type Target = ArgsInner;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.inner
|
|
}
|
|
}
|
|
|
|
fn validate_inner(args: ArgsInner) -> Result<ArgsInner, clap::Error> {
|
|
match &args.command {
|
|
Command::Lex {
|
|
input,
|
|
output_tokens,
|
|
output_symbols,
|
|
} => validate_lex(input, output_tokens, output_symbols)?,
|
|
Command::Syn { input, output_tree } => validate_syn(input, output_tree)?,
|
|
Command::Sem { input, output_tree } => validate_sem(input, output_tree)?,
|
|
Command::Gen {
|
|
input,
|
|
output,
|
|
output_symbols,
|
|
..
|
|
} => validate_gen(input, output, output_symbols)?,
|
|
Command::Com { input, output, .. } => validate_com(input, output)?,
|
|
Command::Int { input } => validate_int(input)?,
|
|
};
|
|
|
|
Ok(args)
|
|
}
|
|
|
|
fn validate_lex(
|
|
input: &PathBuf,
|
|
output_tokens: &PathBuf,
|
|
output_symbols: &PathBuf,
|
|
) -> Result<(), clap::Error> {
|
|
if !input.is_file() {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
format!("Input file '{}' does not exist", input.display()),
|
|
));
|
|
}
|
|
|
|
if input == output_tokens {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
"Input and output files cannot be the same",
|
|
));
|
|
}
|
|
|
|
if input == output_symbols {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
"Input and output files cannot be the same",
|
|
));
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn validate_syn(input: &PathBuf, output_tree: &PathBuf) -> Result<(), clap::Error> {
|
|
if !input.is_file() {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
format!("Input file '{}' does not exist", input.display()),
|
|
));
|
|
}
|
|
|
|
if output_tree == input {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
"Input and output files cannot be the same",
|
|
));
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn validate_sem(input: &PathBuf, output_tree: &PathBuf) -> Result<(), clap::Error> {
|
|
if !input.is_file() {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
format!("Input file '{}' does not exist", input.display()),
|
|
));
|
|
}
|
|
|
|
if output_tree == input {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
"Input and output files cannot be the same",
|
|
));
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn validate_gen(
|
|
input: &PathBuf,
|
|
output: &PathBuf,
|
|
output_symbols: &PathBuf,
|
|
) -> Result<(), clap::Error> {
|
|
if !input.is_file() {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
format!("Input file '{}' does not exist", input.display()),
|
|
));
|
|
}
|
|
|
|
if input == output {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
"Input and output files cannot be the same",
|
|
));
|
|
};
|
|
|
|
if input == output_symbols {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
"Input and output files cannot be the same",
|
|
));
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn validate_com(input: &PathBuf, output: &PathBuf) -> Result<(), clap::Error> {
|
|
if !input.is_file() {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
format!("Input file '{}' does not exist", input.display()),
|
|
));
|
|
}
|
|
|
|
if input == output {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
"Input and output files cannot be the same",
|
|
));
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn validate_int(input: &PathBuf) -> Result<(), clap::Error> {
|
|
if !input.is_file() {
|
|
return Err(clap::Error::raw(
|
|
clap::error::ErrorKind::InvalidValue,
|
|
format!("Input file '{}' does not exist", input.display()),
|
|
));
|
|
}
|
|
|
|
Ok(())
|
|
}
|