parser: fix recursive subshells
This commit is contained in:
parent
903d6dd64f
commit
c49577e924
2 changed files with 44 additions and 46 deletions
|
@ -38,7 +38,7 @@ fn main() {
|
||||||
let stdin = std::io::stdin();
|
let stdin = std::io::stdin();
|
||||||
for line in std::io::BufReader::new(stdin).lines() {
|
for line in std::io::BufReader::new(stdin).lines() {
|
||||||
if let Ok(line) = line {
|
if let Ok(line) = line {
|
||||||
let cmd = sh::parse::parse_cmd( &mut line.chars().peekable() );
|
let cmd = sh::parse::parse_cmd( &mut line.chars().peekable(), 0 );
|
||||||
eprintln!("parsed cmd: {:?}", cmd);
|
eprintln!("parsed cmd: {:?}", cmd);
|
||||||
/*
|
/*
|
||||||
let mut lex = parse::WordLexer::from( line.chars() );
|
let mut lex = parse::WordLexer::from( line.chars() );
|
||||||
|
|
|
@ -30,7 +30,8 @@ where It: Iterator<Item = char> {
|
||||||
(None, true),
|
(None, true),
|
||||||
(Some(' '), true),
|
(Some(' '), true),
|
||||||
(Some('\t'), true),
|
(Some('\t'), true),
|
||||||
(Some('\n'), true)
|
(Some('\n'), true),
|
||||||
|
(Some(')'), false),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +44,8 @@ where It: Iterator<Item = char> {
|
||||||
(Some('|'), false),
|
(Some('|'), false),
|
||||||
(Some('&'), false),
|
(Some('&'), false),
|
||||||
(Some(';'), false),
|
(Some(';'), false),
|
||||||
|
(Some(')'), false),
|
||||||
|
(Some('$'), false),
|
||||||
(Some('\"'), false),
|
(Some('\"'), false),
|
||||||
(Some('\''), false)
|
(Some('\''), false)
|
||||||
])
|
])
|
||||||
|
@ -58,6 +61,7 @@ where It: Iterator<Item = char> {
|
||||||
(Some('|'), false),
|
(Some('|'), false),
|
||||||
(Some('&'), false),
|
(Some('&'), false),
|
||||||
(Some(';'), false),
|
(Some(';'), false),
|
||||||
|
(Some(')'), false),
|
||||||
(Some('\"'), false),
|
(Some('\"'), false),
|
||||||
(Some('\''), false)
|
(Some('\''), false)
|
||||||
])
|
])
|
||||||
|
@ -92,7 +96,8 @@ where It: 'a + Iterator<Item = char> {
|
||||||
|
|
||||||
pub struct SubstLexer<'a, It>
|
pub struct SubstLexer<'a, It>
|
||||||
where It: 'a + Iterator<Item = char> {
|
where It: 'a + Iterator<Item = char> {
|
||||||
chars: &'a mut Peekable<It>
|
chars: &'a mut Peekable<It>,
|
||||||
|
depth: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip_whitespace<It>(chars: &mut Peekable<It>)
|
pub fn skip_whitespace<It>(chars: &mut Peekable<It>)
|
||||||
|
@ -124,12 +129,14 @@ pub fn parse_doublequoted<It>(chars: &mut Peekable<It>) -> Result<WordSegment, L
|
||||||
where It: Iterator<Item = char>
|
where It: Iterator<Item = char>
|
||||||
{
|
{
|
||||||
assert_eq!( chars.next(), Some('\"'));
|
assert_eq!( chars.next(), Some('\"'));
|
||||||
|
|
||||||
|
// todo: allow escaped \"
|
||||||
let quoted = DelimIter::new(chars, vec![(Some('\"'), true)]).try_collect::<String>();
|
let quoted = DelimIter::new(chars, vec![(Some('\"'), true)]).try_collect::<String>();
|
||||||
|
|
||||||
match quoted {
|
match quoted {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
let word = Word {
|
let word = Word {
|
||||||
segments: SubstLexer { chars: &mut s.chars().peekable() }
|
segments: SubstLexer { chars: &mut s.chars().peekable(), depth: 1 }
|
||||||
.try_collect::<Vec<_>>()?
|
.try_collect::<Vec<_>>()?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -213,14 +220,14 @@ where It: Iterator<Item = char>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_cmd<It>(chars: &mut Peekable<It>) -> Result<Option<Command>, LexError>
|
pub fn parse_cmd<It>(chars: &mut Peekable<It>, depth: usize) -> Result<Option<Command>, LexError>
|
||||||
where It: Iterator<Item = char>
|
where It: Iterator<Item = char>
|
||||||
{
|
{
|
||||||
skip_whitespace(chars);
|
skip_whitespace(chars);
|
||||||
match chars.peek() {
|
match chars.peek() {
|
||||||
Some('!') => {
|
Some('!') => {
|
||||||
chars.next();
|
chars.next();
|
||||||
if let Some(cmd) = parse_cmd(chars)? {
|
if let Some(cmd) = parse_cmd(chars, depth)? {
|
||||||
Ok(Some(Command::Negation(Box::new(cmd))))
|
Ok(Some(Command::Negation(Box::new(cmd))))
|
||||||
} else {
|
} else {
|
||||||
Err(LexError::UnexpectedEnd(vec![]))
|
Err(LexError::UnexpectedEnd(vec![]))
|
||||||
|
@ -234,18 +241,14 @@ where It: Iterator<Item = char>
|
||||||
Some(';') => {
|
Some(';') => {
|
||||||
chars.next();
|
chars.next();
|
||||||
|
|
||||||
let tail = parse_cmd( chars ) ?;
|
let tail = parse_cmd( chars, depth ) ?;
|
||||||
match tail {
|
match tail {
|
||||||
Some(Command::Sequence(mut s)) => {
|
Some(Command::Sequence(mut s)) => {
|
||||||
s.insert(0, head);
|
s.insert(0, head);
|
||||||
Ok(Some(Command::Sequence(s)))
|
Ok(Some(Command::Sequence(s)))
|
||||||
}
|
}
|
||||||
Some(tail) => {
|
Some(tail) => Ok(Some(Command::Sequence(vec![ head, tail ]))),
|
||||||
Ok(Some(Command::Sequence(vec![ head, tail ])))
|
None => Ok(Some(head))
|
||||||
}
|
|
||||||
None => {
|
|
||||||
Ok(Some(head))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some('|') => {
|
Some('|') => {
|
||||||
|
@ -254,33 +257,25 @@ where It: Iterator<Item = char>
|
||||||
Some('|') => {
|
Some('|') => {
|
||||||
chars.next();
|
chars.next();
|
||||||
|
|
||||||
let tail = parse_cmd( chars ) ?;
|
let tail = parse_cmd( chars, depth ) ?;
|
||||||
match tail {
|
match tail {
|
||||||
Some(Command::ShortCircuitDisjunction(mut s)) => {
|
Some(Command::ShortCircuitDisjunction(mut s)) => {
|
||||||
s.insert(0, head);
|
s.insert(0, head);
|
||||||
Ok(Some(Command::ShortCircuitDisjunction(s)))
|
Ok(Some(Command::ShortCircuitDisjunction(s)))
|
||||||
}
|
}
|
||||||
Some(tail) => {
|
Some(tail) => Ok(Some(Command::ShortCircuitDisjunction(vec![ head, tail ]))),
|
||||||
Ok(Some(Command::ShortCircuitDisjunction(vec![ head, tail ])))
|
None => Err(LexError::UnexpectedEnd(vec![Some('|')]))
|
||||||
}
|
|
||||||
None => {
|
|
||||||
Err(LexError::UnexpectedEnd(vec![Some('|')]))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let tail = parse_cmd( chars ) ?;
|
let tail = parse_cmd( chars, depth ) ?;
|
||||||
match tail {
|
match tail {
|
||||||
Some(Command::Pipeline(mut s)) => {
|
Some(Command::Pipeline(mut s)) => {
|
||||||
s.insert(0, head);
|
s.insert(0, head);
|
||||||
Ok(Some(Command::Pipeline(s)))
|
Ok(Some(Command::Pipeline(s)))
|
||||||
}
|
}
|
||||||
Some(tail) => {
|
Some(tail) => Ok(Some(Command::Pipeline(vec![ head, tail ]))),
|
||||||
Ok(Some(Command::Pipeline(vec![ head, tail ])))
|
None => Err(LexError::UnexpectedEnd(vec![]))
|
||||||
}
|
|
||||||
None => {
|
|
||||||
Err(LexError::UnexpectedEnd(vec![]))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,23 +286,17 @@ where It: Iterator<Item = char>
|
||||||
Some('&') => {
|
Some('&') => {
|
||||||
chars.next();
|
chars.next();
|
||||||
|
|
||||||
let tail = parse_cmd( chars ) ?;
|
let tail = parse_cmd( chars, depth ) ?;
|
||||||
match tail {
|
match tail {
|
||||||
Some(Command::ShortCircuitConjunction(mut s)) => {
|
Some(Command::ShortCircuitConjunction(mut s)) => {
|
||||||
s.insert(0, head);
|
s.insert(0, head);
|
||||||
Ok(Some(Command::ShortCircuitConjunction(s)))
|
Ok(Some(Command::ShortCircuitConjunction(s)))
|
||||||
}
|
}
|
||||||
Some(tail) => {
|
Some(tail) => Ok(Some(Command::ShortCircuitConjunction(vec![ head, tail ]))),
|
||||||
Ok(Some(Command::ShortCircuitConjunction(vec![ head, tail ])))
|
None => Err(LexError::UnexpectedEnd(vec![Some('&'), Some('&')]))
|
||||||
}
|
|
||||||
None => {
|
|
||||||
Err(LexError::UnexpectedEnd(vec![Some('&'), Some('&')]))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(c) => {
|
Some(c) => Err(LexError::UnexpectedToken(*c)),
|
||||||
Err(LexError::UnexpectedToken(*c))
|
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
// todo:
|
// todo:
|
||||||
// background job
|
// background job
|
||||||
|
@ -315,12 +304,17 @@ where It: Iterator<Item = char>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(c) => {
|
Some(')') => {
|
||||||
Err(LexError::UnexpectedToken(*c))
|
eprintln!("got )");
|
||||||
}
|
chars.next();
|
||||||
None => {
|
if depth > 0 {
|
||||||
Ok(Some(head))
|
Ok(Some(head))
|
||||||
|
} else {
|
||||||
|
Err(LexError::UnexpectedToken(')'))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Some(c) => Err(LexError::UnexpectedToken(*c)),
|
||||||
|
None => Ok(Some(head))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -351,20 +345,23 @@ where It: 'a + Iterator<Item = char> {
|
||||||
// Subshell
|
// Subshell
|
||||||
Some('(') => {
|
Some('(') => {
|
||||||
self.chars.next();
|
self.chars.next();
|
||||||
|
/*
|
||||||
let subcmd_str = DelimIter::new(&mut self.chars, vec![(Some(')'), true)]).try_collect::<String>();
|
let subcmd_str = DelimIter::new(&mut self.chars, vec![(Some(')'), true)]).try_collect::<String>();
|
||||||
match subcmd_str {
|
match subcmd_str {
|
||||||
Ok(subcmd_str) => {
|
Ok(subcmd_str) => {
|
||||||
match parse_cmd(&mut subcmd_str.chars().peekable()) {
|
*/
|
||||||
|
match parse_cmd(&mut self.chars, 1) {
|
||||||
Ok(Some(subcmd)) => {
|
Ok(Some(subcmd)) => {
|
||||||
Some(Ok(WordSegment::Subshell(subcmd)))
|
Some(Ok(WordSegment::Subshell(subcmd)))
|
||||||
}
|
}
|
||||||
Ok(None) => None,
|
Ok(None) => None,
|
||||||
Err(err) => Some(Err(err))
|
Err(err) => Some(Err(err))
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
}
|
}
|
||||||
Err(err) => Some(Err(err))
|
Err(err) => Some(Err(err))
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// plain parameter name e.g. `$PARAM`
|
// plain parameter name e.g. `$PARAM`
|
||||||
|
@ -426,8 +423,9 @@ where It: 'a + Iterator<Item = char> {
|
||||||
Some('"') => { Some(parse_doublequoted(self.chars)) },
|
Some('"') => { Some(parse_doublequoted(self.chars)) },
|
||||||
Some('\'') => { Some(parse_quoted(self.chars)) },
|
Some('\'') => { Some(parse_quoted(self.chars)) },
|
||||||
Some('$') => {
|
Some('$') => {
|
||||||
SubstLexer{ chars: &mut self.chars }.next()
|
SubstLexer{ chars: &mut self.chars, depth: 1 }.next()
|
||||||
}
|
}
|
||||||
|
Some(')') => { None }
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
let s : Result<String, LexError> = DelimIter::new_shell_word(self.chars).collect();
|
let s : Result<String, LexError> = DelimIter::new_shell_word(self.chars).collect();
|
||||||
match s {
|
match s {
|
||||||
|
|
Loading…
Reference in a new issue