1
0
Files
developing-compilers/src/cli.rs
2024-11-13 20:24:40 +03:00

232 lines
5.6 KiB
Rust

use std::ops::Deref;
use std::path::PathBuf;
use clap::{CommandFactory, Parser, Subcommand};
use developing_compilers::ast::optimization::OLevel;
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,
#[clap(short, long, default_value_t = OLevel::None)]
optimization_level: OLevel,
},
Gen {
mode: GenMode,
#[clap(short, long, default_value_t = OLevel::None)]
optimization_level: OLevel,
input: PathBuf,
output: PathBuf,
output_symbols: PathBuf,
},
Com {
#[clap(short, long, default_value_t = OLevel::None)]
optimization_level: OLevel,
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(())
}