diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 340c982..a8fbb46 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -6,6 +6,10 @@ == [Unreleased] +== Added + +- implement literal strings + == Fixed - fix serializing strings containing `:` diff --git a/src/parser.rs b/src/parser.rs index 7d6c20d..7b3bdd2 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -62,6 +62,13 @@ fn identifier(input: Span) -> IResult { })(input) } +fn literal_string(input: Span) -> IResult { + map( + delimited(tag("\"\"\""), take_until("\"\"\""), tag("\"\"\"")), + |val: Span| *val.fragment(), + )(input) +} + fn string_content(input: Span) -> IResult { let buf = input.fragment(); let mut escaped = false; @@ -99,7 +106,7 @@ fn delimited_string(input: Span) -> IResult { } fn string(input: Span) -> IResult { - alt((identifier, delimited_string))(input) + alt((identifier, literal_string, delimited_string))(input) } fn line_comment(input: Span) -> IResult { @@ -340,6 +347,41 @@ mod test { } } + #[test] + fn parse_literal_string() { + assert_ok!(r#""""""""#, literal_string, "", ""); + assert_ok!(r#""""foo""""#, literal_string, "", "foo"); + assert_ok!(r#""""foo"""""#, literal_string, "\"", "foo"); + assert_ok!(r#"""""foo""""#, literal_string, "", "\"foo"); + assert_ok!(r#""""\n""""#, literal_string, "", "\\n"); + + { + let raw = r#" +This is a lengthy description! + +It contains line breaks. + +Escape sequences, like \n and \t, are parsed literally. +"Quoted strings are fine", so are two sucessive quotes: "". +"#; + + let input = format!(r#""""{}""""#, raw); + + assert_ok!(input.as_str(), literal_string, "", raw); + } + + { + let input = Span::from(r#"""""""#); + assert_eq!( + literal_string(input), + Err(Err::Error(Error::new( + unsafe { Span::new_from_raw_offset(3, 1, "\"\"", ()) }, + ErrorKind::TakeUntil + ))) + ); + } + } + #[test] fn parse_line_comment() { assert_ok!("// foo", line_comment, "", " foo");