From 687831816db94c6d3364b4c3ca8d974f83741dd8 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Thu, 26 Jan 2023 23:54:24 -0800 Subject: [PATCH] Allow multiple attributes on one line (#1537) --- src/parser.rs | 30 +++++++++++++--------- tests/attributes.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 10a207e..0ac7d36 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -854,19 +854,25 @@ impl<'tokens, 'src> Parser<'tokens, 'src> { let mut attributes = BTreeMap::new(); while self.accepted(BracketL)? { - let name = self.parse_name()?; - let attribute = Attribute::from_name(name).ok_or_else(|| { - name.error(CompileErrorKind::UnknownAttribute { - attribute: name.lexeme(), - }) - })?; - if let Some(line) = attributes.get(&attribute) { - return Err(name.error(CompileErrorKind::DuplicateAttribute { - attribute: name.lexeme(), - first: *line, - })); + loop { + let name = self.parse_name()?; + let attribute = Attribute::from_name(name).ok_or_else(|| { + name.error(CompileErrorKind::UnknownAttribute { + attribute: name.lexeme(), + }) + })?; + if let Some(line) = attributes.get(&attribute) { + return Err(name.error(CompileErrorKind::DuplicateAttribute { + attribute: name.lexeme(), + first: *line, + })); + } + attributes.insert(attribute, name.line); + + if !self.accepted(TokenKind::Comma)? { + break; + } } - attributes.insert(attribute, name.line); self.expect(BracketR)?; self.expect_eol()?; } diff --git a/tests/attributes.rs b/tests/attributes.rs index 993e9ee..accfde8 100644 --- a/tests/attributes.rs +++ b/tests/attributes.rs @@ -41,3 +41,65 @@ fn duplicate_attributes_are_disallowed() { .status(1) .run(); } + +#[test] +fn multiple_attributes_one_line() { + Test::new() + .justfile( + " + [macos, windows,linux] + [no-exit-message] + foo: + exit 1 + ", + ) + .stderr("exit 1\n") + .status(1) + .run(); +} + +#[test] +fn multiple_attributes_one_line_error_message() { + Test::new() + .justfile( + " + [macos, windows linux] + [no-exit-message] + foo: + exit 1 + ", + ) + .stderr( + " + error: Expected ']' or ',', but found identifier + | + 1 | [macos, windows linux] + | ^^^^^ + ", + ) + .status(1) + .run(); +} + +#[test] +fn multiple_attributes_one_line_duplicate_check() { + Test::new() + .justfile( + " + [macos, windows, linux] + [linux] + foo: + exit 1 + ", + ) + .stderr( + " + error: Recipe attribute `linux` first used on line 1 is duplicated on line 2 + | + 2 | [linux] + | ^^^^^ + ", + ) + .status(1) + .run(); +}