Skip to content

Commit

Permalink
Parse all types of CaseContinuation in a case item
Browse files Browse the repository at this point in the history
Previously, the parser only recognized the `;;` terminator for a case
item. This commit changes the parser to recognize all types of
CaseContinuation, including `;&` and `;;&`.
  • Loading branch information
magicant committed Nov 11, 2024
1 parent 144261c commit c381f93
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 5 deletions.
3 changes: 2 additions & 1 deletion yash-syntax/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `SemicolonAnd`, `SemicolonSemicolonAnd`, and `SemicolonBar` variants
are added to the `parser::lex::Operator` enum.
- The `parser::Parser::case_item` and `syntax::CaseItem::from_str` methods
now consume a trailing terminator token, if any.
now consume a trailing terminator token, if any. The terminator can be
not only `;;`, but also `;&`, `;|`, or `;;&`.

## [0.12.1] - 2024-11-10

Expand Down
28 changes: 24 additions & 4 deletions yash-syntax/src/parser/case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ use super::core::Result;
use super::error::Error;
use super::error::SyntaxError;
use super::lex::Keyword::{Case, Esac, In};
use super::lex::Operator::{Bar, CloseParen, Newline, OpenParen, SemicolonSemicolon};
use super::lex::Operator::{Bar, CloseParen, Newline, OpenParen};
use super::lex::TokenId::{self, EndOfInput, Operator, Token};
use crate::syntax::CaseContinuation;
use crate::syntax::CaseItem;
use crate::syntax::CompoundCommand;

Expand Down Expand Up @@ -102,9 +101,13 @@ impl Parser<'_, '_> {
}

let body = self.maybe_compound_list_boxed().await?;
let continuation = CaseContinuation::default();

let continued = self.peek_token().await?.id == Operator(SemicolonSemicolon);
let continuation = match self.peek_token().await?.id {
Operator(op) => op.try_into().ok(),
_ => None,
};
let continued = continuation.is_some();
let continuation = continuation.unwrap_or_default();
if continued {
self.take_token_raw().await?;
}
Expand Down Expand Up @@ -190,6 +193,7 @@ mod tests {
use crate::alias::{AliasSet, EmptyGlossary, HashEntry};
use crate::source::Location;
use crate::source::Source;
use crate::syntax::CaseContinuation;
use assert_matches::assert_matches;
use futures_util::FutureExt;

Expand Down Expand Up @@ -321,6 +325,22 @@ mod tests {
assert_eq!(next.id, EndOfInput);
}

#[test]
fn parser_case_item_with_semicolon_and() {
let mut lexer = Lexer::from_memory("foo);&", Source::Unknown);
let mut parser = Parser::new(&mut lexer, &EmptyGlossary);

let (item, continued) = parser.case_item().now_or_never().unwrap().unwrap().unwrap();
assert_eq!(item.patterns.len(), 1);
assert_eq!(item.patterns[0].to_string(), "foo");
assert_eq!(item.body.0, []);
assert_eq!(item.continuation, CaseContinuation::FallThrough);
assert!(continued);

let next = parser.peek_token().now_or_never().unwrap().unwrap();
assert_eq!(next.id, EndOfInput);
}

#[test]
fn parser_case_item_missing_pattern_without_open_paren() {
let mut lexer = Lexer::from_memory(")", Source::Unknown);
Expand Down

0 comments on commit c381f93

Please sign in to comment.