#, "/source/src/trinitry.pest) file.")]
use std::{fmt::Display, str::FromStr};
use parsing::{Rule, TrinitryParser};
use pest::error::Error;
mod parsing;
pub struct Trinitry {
command: String,
arguments: Vec<String>,
}
impl Trinitry {
pub fn new(input: &str) -> Result<Self, <Self as FromStr>::Err> {
input.parse()
}
pub fn command(&self) -> &str {
&self.command
}
pub fn arguments(&self) -> &[String] {
&self.arguments
}
}
impl FromStr for Trinitry {
type Err = Error<Rule>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parsed = TrinitryParser::new(s)?;
Ok(Self::from(parsed))
}
}
impl From<TrinitryParser<'_>> for Trinitry {
fn from(parsed: TrinitryParser) -> Self {
let command = {
let command: Vec<_> = parsed.0.clone().find_tagged("command").collect();
debug_assert_eq!(command.len(), 1);
command
.first()
.expect("This should contain exactly one element")
.to_owned()
};
let arguments: Vec<_> = parsed.0.clone().find_tagged("argument").collect();
Self {
command: command.as_str().to_owned(),
arguments: arguments
.iter()
.map(|arg| {
let mut arg = arg.as_str().trim();
arg = if let Some(new_arg) = arg.strip_prefix("\"") {
new_arg
} else {
arg
};
arg = if let Some(new_arg) = arg.strip_suffix("\"") {
new_arg
} else {
arg
};
arg = if let Some(new_arg) = arg.strip_prefix("'") {
new_arg
} else {
arg
};
arg = if let Some(new_arg) = arg.strip_suffix("'") {
new_arg
} else {
arg
};
arg.to_owned()
})
.collect(),
}
}
}
impl Display for Trinitry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.arguments.is_empty() {
f.write_str(&self.command)
} else {
f.write_fmt(format_args!(
"{} {}",
&self.command,
&self.arguments.join(" ")
))
}
}
}
mod tests;
#[cfg(test)]
mod test {
use crate::Trinitry;
#[test]
fn parse_cmd() {
let string = "quit";
let p = Trinitry::new(string).unwrap_or_else(|e| {
panic!("{}", e);
});
assert_eq!(&p.command, "quit");
assert!(&p.arguments.is_empty());
}
#[test]
fn parse_arg_clean() {
let string = r##"lua print("Hi")"##;
let p = Trinitry::new(string).unwrap_or_else(|e| {
panic!("{}", e);
});
assert_eq!(&p.command, "lua");
assert_eq!(&p.arguments[0], r#"print("Hi")"#);
}
#[test]
fn parse_arg_quote() {
let string = r##"write "some 'file' name""##;
let p = Trinitry::new(string).unwrap_or_else(|e| {
panic!("{}", e);
});
assert_eq!(&p.command, "write");
assert_eq!(&p.arguments[0], "some 'file' name");
}
#[test]
fn parse_arg_single_quote() {
let string = r##"write 'some "file" name'"##;
let p = Trinitry::new(string).unwrap_or_else(|e| {
panic!("{}", e);
});
assert_eq!(&p.command, "write");
assert_eq!(&p.arguments[0], "some \"file\" name");
}
#[test]
fn parse_arg_multi() {
let string = r##"write 'some "file" name' "other name" last"##;
let p = Trinitry::new(string).unwrap_or_else(|e| {
panic!("{}", e);
});
let expected_args = vec!["some \"file\" name", "other name", "last"]
.iter()
.map(|str| (*str).to_owned())
.collect::<Vec<String>>();
assert_eq!(&p.command, "write");
assert_eq!(&p.arguments, &expected_args);
}
}