1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

expr: Do not parse arguments using clap

This commit is contained in:
Dorian Peron 2025-02-24 02:42:27 +01:00
parent 81048228cf
commit 44077e37a8
2 changed files with 33 additions and 20 deletions

View file

@ -94,16 +94,29 @@ pub fn uu_app() -> Command {
pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// For expr utility we do not want getopts. // For expr utility we do not want getopts.
// The following usage should work without escaping hyphens: `expr -15 = 1 + 2 \* \( 3 - -4 \)` // The following usage should work without escaping hyphens: `expr -15 = 1 + 2 \* \( 3 - -4 \)`
let matches = uu_app().try_get_matches_from(args)?; let args: Vec<String> = args
let token_strings: Vec<&str> = matches .skip(1) // Skip binary name
.get_many::<String>(options::EXPRESSION) .map(|a| a.to_string_lossy().to_string())
.map(|v| v.into_iter().map(|s| s.as_ref()).collect::<Vec<_>>()) .collect();
.unwrap_or_default();
let res: String = AstNode::parse(&token_strings)?.eval()?.eval_as_string(); if args.len() == 1 && args[0] == "--help" {
println!("{res}"); let _ = uu_app().print_help();
if !is_truthy(&res.into()) { } else if args.len() == 1 && args[0] == "--version" {
return Err(1.into()); println!("{} {}", uucore::util_name(), crate_version!())
} else {
// The first argument may be "--" and should be be ignored.
let args = if !args.is_empty() && args[0] == "--" {
&args[1..]
} else {
&args
};
let res: String = AstNode::parse(args)?.eval()?.eval_as_string();
println!("{res}");
if !is_truthy(&res.into()) {
return Err(1.into());
}
} }
Ok(()) Ok(())
} }

View file

@ -365,7 +365,7 @@ pub enum AstNode {
} }
impl AstNode { impl AstNode {
pub fn parse(input: &[&str]) -> ExprResult<Self> { pub fn parse(input: &[impl AsRef<str>]) -> ExprResult<Self> {
Parser::new(input).parse() Parser::new(input).parse()
} }
@ -427,13 +427,13 @@ impl AstNode {
} }
} }
struct Parser<'a> { struct Parser<'a, S: AsRef<str>> {
input: &'a [&'a str], input: &'a [S],
index: usize, index: usize,
} }
impl<'a> Parser<'a> { impl<'a, S: AsRef<str>> Parser<'a, S> {
fn new(input: &'a [&'a str]) -> Self { fn new(input: &'a [S]) -> Self {
Self { input, index: 0 } Self { input, index: 0 }
} }
@ -441,19 +441,19 @@ impl<'a> Parser<'a> {
let next = self.input.get(self.index); let next = self.input.get(self.index);
if let Some(next) = next { if let Some(next) = next {
self.index += 1; self.index += 1;
Ok(next) Ok(next.as_ref())
} else { } else {
// The indexing won't panic, because we know that the input size // The indexing won't panic, because we know that the input size
// is greater than zero. // is greater than zero.
Err(ExprError::MissingArgument( Err(ExprError::MissingArgument(
self.input[self.index - 1].into(), self.input[self.index - 1].as_ref().into(),
)) ))
} }
} }
fn accept<T>(&mut self, f: impl Fn(&str) -> Option<T>) -> Option<T> { fn accept<T>(&mut self, f: impl Fn(&str) -> Option<T>) -> Option<T> {
let next = self.input.get(self.index)?; let next = self.input.get(self.index)?;
let tok = f(next); let tok = f(next.as_ref());
if let Some(tok) = tok { if let Some(tok) = tok {
self.index += 1; self.index += 1;
Some(tok) Some(tok)
@ -468,7 +468,7 @@ impl<'a> Parser<'a> {
} }
let res = self.parse_expression()?; let res = self.parse_expression()?;
if let Some(arg) = self.input.get(self.index) { if let Some(arg) = self.input.get(self.index) {
return Err(ExprError::UnexpectedArgument(arg.to_string())); return Err(ExprError::UnexpectedArgument(arg.as_ref().into()));
} }
Ok(res) Ok(res)
} }
@ -556,12 +556,12 @@ impl<'a> Parser<'a> {
// at `self.index - 1`. So this indexing won't panic. // at `self.index - 1`. So this indexing won't panic.
Ok(_) => { Ok(_) => {
return Err(ExprError::ExpectedClosingBraceInsteadOf( return Err(ExprError::ExpectedClosingBraceInsteadOf(
self.input[self.index - 1].into(), self.input[self.index - 1].as_ref().into(),
)); ));
} }
Err(ExprError::MissingArgument(_)) => { Err(ExprError::MissingArgument(_)) => {
return Err(ExprError::ExpectedClosingBraceAfter( return Err(ExprError::ExpectedClosingBraceAfter(
self.input[self.index - 1].into(), self.input[self.index - 1].as_ref().into(),
)); ));
} }
Err(e) => return Err(e), Err(e) => return Err(e),