1
Fork 0

Merge branch 'fix/backslash'

* fix/backslash:
  fix(parser): Support backslashes in delimited strings
This commit is contained in:
Lucas Schwiderski 2023-02-24 11:26:27 +01:00
commit 25b4083379
Signed by: lucas
GPG key ID: AA12679AAA6DF4D8

View file

@ -1,13 +1,11 @@
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::{escaped, tag, take_until}; use nom::bytes::complete::{tag, take_until};
use nom::character::complete::{ use nom::character::complete::{alpha1, alphanumeric1, char, digit1, not_line_ending, one_of};
alpha1, alphanumeric1, char, digit1, none_of, not_line_ending, one_of,
};
use nom::combinator::{cut, eof, map, map_res, opt, recognize, value}; use nom::combinator::{cut, eof, map, map_res, opt, recognize, value};
use nom::multi::{many0_count, many1_count}; use nom::multi::{many0_count, many1_count};
use nom::number::complete::double; use nom::number::complete::double;
use nom::sequence::{delimited, pair, preceded, terminated, tuple}; use nom::sequence::{delimited, pair, preceded, terminated, tuple};
use nom::IResult; use nom::{IResult, Slice};
use nom_locate::LocatedSpan; use nom_locate::LocatedSpan;
pub(crate) type Span<'a> = LocatedSpan<&'a str>; pub(crate) type Span<'a> = LocatedSpan<&'a str>;
@ -67,14 +65,35 @@ fn identifier(input: Span) -> IResult<Span, &str> {
} }
fn string_content(input: Span) -> IResult<Span, &str> { fn string_content(input: Span) -> IResult<Span, &str> {
// TODO: Handle Unicode escapes let buf = input.fragment();
map( let mut escaped = false;
alt(( let mut i = 0;
escaped(none_of("\n\\\""), '\\', one_of(r#""rtn\"#)),
tag(""), for (j, ch) in buf.char_indices() {
)), i = j;
|val: Span| *val.fragment(), match ch {
)(input) '\\' if !escaped => {
escaped = true;
}
'\n' if !escaped => {
let err = nom::error::Error {
input: input.slice(j..),
code: nom::error::ErrorKind::Char,
};
return Err(nom::Err::Error(err));
}
'"' if !escaped => {
return Ok((input.slice(j..), &buf[0..j]));
}
_ => escaped = false,
}
}
let err = nom::error::Error {
input: input.slice((i + 1)..),
code: nom::error::ErrorKind::Char,
};
Err(nom::Err::Failure(err))
} }
fn delimited_string(input: Span) -> IResult<Span, &str> { fn delimited_string(input: Span) -> IResult<Span, &str> {
@ -291,6 +310,7 @@ mod test {
assert_ok!(r#""foo123""#, delimited_string, "", "foo123"); assert_ok!(r#""foo123""#, delimited_string, "", "foo123");
assert_ok!(r#""123foo""#, delimited_string, "", "123foo"); assert_ok!(r#""123foo""#, delimited_string, "", "123foo");
assert_ok!(r#""foo\"bar""#, delimited_string, "", "foo\\\"bar"); assert_ok!(r#""foo\"bar""#, delimited_string, "", "foo\\\"bar");
assert_ok!(r#""foo\\bar""#, delimited_string, "", "foo\\\\bar");
assert_ok!(r#""foo/bar""#, delimited_string, "", "foo/bar"); assert_ok!(r#""foo/bar""#, delimited_string, "", "foo/bar");
assert_err!("foo\"", delimited_string, ErrorKind::Char); assert_err!("foo\"", delimited_string, ErrorKind::Char);
@ -364,4 +384,12 @@ packages = [
], ],
); );
} }
// Regression test for #2
#[test]
fn parse_windows_path() {
let text = "C:\\Users\\public\\test.txt";
let sjson = format!(r#""{}""#, text);
check_parse_result(sjson, [Token::String(String::from(text))]);
}
} }