parent
fc5d8b25fb
commit
81896339a3
1 changed files with 41 additions and 13 deletions
|
@ -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))]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue