Allow escaping newlines (#1551)

This commit is contained in:
Ian Douglas Scott 2023-07-25 02:05:47 -07:00 committed by GitHub
parent f04de75609
commit 30bcf28fde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 0 deletions

View File

@ -481,6 +481,7 @@ impl<'src> Lexer<'src> {
',' => self.lex_single(Comma), ',' => self.lex_single(Comma),
'/' => self.lex_single(Slash), '/' => self.lex_single(Slash),
':' => self.lex_colon(), ':' => self.lex_colon(),
'\\' => self.lex_escape(),
'=' => self.lex_choices('=', &[('=', EqualsEquals), ('~', EqualsTilde)], Equals), '=' => self.lex_choices('=', &[('=', EqualsEquals), ('~', EqualsTilde)], Equals),
'@' => self.lex_single(At), '@' => self.lex_single(At),
'[' => self.lex_delimiter(BracketL), '[' => self.lex_delimiter(BracketL),
@ -709,6 +710,31 @@ impl<'src> Lexer<'src> {
Ok(()) Ok(())
} }
/// Lex an token starting with '\' escape
fn lex_escape(&mut self) -> CompileResult<'src, ()> {
self.presume('\\')?;
// Treat newline escaped with \ as whitespace
if self.accepted('\n')? {
while self.next_is_whitespace() {
self.advance()?;
}
self.token(Whitespace);
} else if self.accepted('\r')? {
if !self.accepted('\n')? {
return Err(self.error(UnpairedCarriageReturn));
}
while self.next_is_whitespace() {
self.advance()?;
}
self.token(Whitespace);
} else if let Some(character) = self.next {
return Err(self.error(CompileErrorKind::InvalidEscapeSequence { character }));
}
Ok(())
}
/// Lex a carriage return and line feed /// Lex a carriage return and line feed
fn lex_eol(&mut self) -> CompileResult<'src, ()> { fn lex_eol(&mut self) -> CompileResult<'src, ()> {
if self.accepted('\r')? { if self.accepted('\r')? {

View File

@ -63,6 +63,7 @@ mod json;
mod line_prefixes; mod line_prefixes;
mod misc; mod misc;
mod multibyte_char; mod multibyte_char;
mod newline_escape;
mod no_cd; mod no_cd;
mod no_exit_message; mod no_exit_message;
mod os_attributes; mod os_attributes;

77
tests/newline_escape.rs Normal file
View File

@ -0,0 +1,77 @@
use super::*;
#[test]
fn newline_escape_deps() {
Test::new()
.justfile(
"
default: a \\
b \\
c
a:
echo a
b:
echo b
c:
echo c
",
)
.stdout("a\nb\nc\n")
.stderr("echo a\necho b\necho c\n")
.run();
}
#[test]
fn newline_escape_deps_no_indent() {
Test::new()
.justfile(
"
default: a\\
b\\
c
a:
echo a
b:
echo b
c:
echo c
",
)
.stdout("a\nb\nc\n")
.stderr("echo a\necho b\necho c\n")
.run();
}
#[test]
fn newline_escape_deps_linefeed() {
Test::new()
.justfile(
"
default: a\\\r
b
a:
echo a
b:
echo b
",
)
.stdout("a\nb\n")
.stderr("echo a\necho b\n")
.run();
}
#[test]
fn newline_escape_deps_invalid_esc() {
Test::new()
.justfile(
"
default: a\\ b
",
)
.stdout("")
.stderr(
"error: `\\ ` is not a valid escape sequence\n |\n1 | default: a\\ b\n | ^\n",
)
.status(EXIT_FAILURE)
.run();
}