@@ -766,13 +766,13 @@ fn equals_sign(input: &mut Input<'_>) -> PResult<()> {
766766}
767767
768768/// ```text
769- /// quoted-string := '"' ( single-line-string-body | newline multi-line-string-body newline unicode-space*) '"'
769+ /// quoted-string := '"' single-line-string-body '"' | '"""' newline multi-line-string-body newline unicode-space*) '"" "'
770770/// single-line-string-body := (string-character - newline)*
771771/// multi-line-string-body := string-character*
772772/// ```
773773fn quoted_string < ' s > ( input : & mut Input < ' s > ) -> PResult < Option < KdlValue > > {
774- "\" " . parse_next ( input) ?;
775- let is_multiline = opt ( newline ) . parse_next ( input ) ? . is_some ( ) ;
774+ let quotes = alt ( ( ( "\" \" \" " , newline ) . take ( ) , " \" " ) ) . parse_next ( input) ?;
775+ let is_multiline = quotes . len ( ) > 1 ;
776776 let ml_prefix: Option < String > = if is_multiline {
777777 Some (
778778 peek ( preceded (
@@ -782,10 +782,13 @@ fn quoted_string<'s>(input: &mut Input<'s>) -> PResult<Option<KdlValue>> {
782782 repeat ( 0 .., ( not ( newline) , opt ( ws_escape) , string_char) ) . map ( |( ) | ( ) ) ,
783783 newline,
784784 ) ,
785- peek ( terminated ( repeat ( 0 .., unicode_space) . map ( |( ) | ( ) ) , "\" " ) ) ,
785+ peek ( terminated (
786+ repeat ( 0 .., unicode_space) . map ( |( ) | ( ) ) ,
787+ "\" \" \" " ,
788+ ) ) ,
786789 )
787790 . map ( |( ( ) , ( ) ) | ( ) ) ,
788- terminated ( repeat ( 0 .., unicode_space) . map ( |( ) | ( ) ) . take ( ) , "\" " ) ,
791+ terminated ( repeat ( 0 .., unicode_space) . map ( |( ) | ( ) ) . take ( ) , "\" \" \" " ) ,
789792 ) )
790793 . parse_next ( input) ?
791794 . to_string ( ) ,
@@ -814,7 +817,7 @@ fn quoted_string<'s>(input: &mut Input<'s>) -> PResult<Option<KdlValue>> {
814817 (
815818 & prefix[ ..] ,
816819 repeat ( 0 .., unicode_space) . map ( |( ) | ( ) ) . take ( ) ,
817- peek ( "\" " ) ,
820+ peek ( "\" \" \" " ) ,
818821 ) ,
819822 )
820823 . map ( |( s, _) : ( Vec < String > , ( _ , _ , _ ) ) | {
@@ -836,9 +839,12 @@ fn quoted_string<'s>(input: &mut Input<'s>) -> PResult<Option<KdlValue>> {
836839 . resume_after ( quoted_string_badval)
837840 . parse_next ( input) ?
838841 } ;
839- cut_err ( "\" " )
840- . context ( lbl ( "closing quote" ) )
841- . parse_next ( input) ?;
842+ let closing_quotes = if is_multiline {
843+ "\" \" \" " . context ( lbl ( "multiline string closing quotes" ) )
844+ } else {
845+ "\" " . context ( lbl ( "string closing quote" ) )
846+ } ;
847+ cut_err ( closing_quotes) . parse_next ( input) ?;
842848 Ok ( body. map ( KdlValue :: String ) )
843849}
844850
@@ -903,13 +909,15 @@ fn escaped_char(input: &mut Input<'_>) -> PResult<char> {
903909}
904910
905911/// `raw-string := '#' raw-string-quotes '#' | '#' raw-string '#'`
906- /// `raw-string-quotes := '"' ( single-line-raw-string-body | newline multi-line-raw-string-body newline unicode-space*) '"'`
912+ /// `raw-string-quotes := '"' single-line-raw-string-body '"' | '"""' newline multi-line-raw-string-body newline unicode-space*) '"" "'`
907913/// `single-line-raw-string-body := (unicode - newline - disallowed-literal-code-points)*`
908914/// `multi-line-raw-string-body := (unicode - disallowed-literal-code-points)`
909915fn raw_string ( input : & mut Input < ' _ > ) -> PResult < Option < KdlValue > > {
910916 let hashes: String = repeat ( 1 .., "#" ) . parse_next ( input) ?;
911- "\" " . parse_next ( input) ?;
912- let is_multiline = opt ( newline) . parse_next ( input) ?. is_some ( ) ;
917+ let quotes = alt ( ( ( "\" \" \" " , newline) . take ( ) , "\" " ) ) . parse_next ( input) ?;
918+ let is_multiline = quotes. len ( ) > 1 ;
919+ dbg ! ( & quotes) ;
920+ dbg ! ( is_multiline) ;
913921 let ml_prefix: Option < String > = if is_multiline {
914922 Some (
915923 peek ( preceded (
@@ -921,7 +929,7 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
921929 (
922930 not ( newline) ,
923931 not ( disallowed_unicode) ,
924- not ( ( "\" " , & hashes[ ..] ) ) ,
932+ not ( ( "\" \" \" " , & hashes[ ..] ) ) ,
925933 any,
926934 ) ,
927935 )
@@ -930,13 +938,13 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
930938 ) ,
931939 peek ( terminated (
932940 repeat ( 0 .., unicode_space) . map ( |( ) | ( ) ) ,
933- ( "\" " , & hashes[ ..] ) ,
941+ ( "\" \" \" " , & hashes[ ..] ) ,
934942 ) ) ,
935943 )
936944 . map ( |( ( ) , ( ) ) | ( ) ) ,
937945 terminated (
938946 repeat ( 0 .., unicode_space) . map ( |( ) | ( ) ) . take ( ) ,
939- ( "\" " , & hashes[ ..] ) ,
947+ ( "\" \" \" " , & hashes[ ..] ) ,
940948 ) ,
941949 ) )
942950 . parse_next ( input) ?
@@ -945,6 +953,7 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
945953 } else {
946954 None
947955 } ;
956+ dbg ! ( & ml_prefix) ;
948957 let body: Option < String > = if let Some ( prefix) = ml_prefix {
949958 repeat_till (
950959 0 ..,
@@ -955,7 +964,7 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
955964 newline. take ( ) . map ( |_| "\n " . to_string ( ) ) ,
956965 repeat_till (
957966 0 ..,
958- ( not ( newline) , not ( ( "\" " , & hashes[ ..] ) ) , any)
967+ ( not ( newline) , not ( ( "\" \" \" " , & hashes[ ..] ) ) , any)
959968 . map ( |( ( ) , ( ) , _) | ( ) )
960969 . take ( ) ,
961970 newline,
@@ -968,7 +977,7 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
968977 (
969978 & prefix[ ..] ,
970979 repeat ( 0 .., unicode_space) . map ( |( ) | ( ) ) . take ( ) ,
971- peek ( ( "\" " , & hashes[ ..] ) ) ,
980+ peek ( ( "\" \" \" " , & hashes[ ..] ) ) ,
972981 ) ,
973982 )
974983 . map ( |( s, _) : ( Vec < String > , ( _ , _ , _ ) ) | {
@@ -996,9 +1005,12 @@ fn raw_string(input: &mut Input<'_>) -> PResult<Option<KdlValue>> {
9961005 . resume_after ( raw_string_badval)
9971006 . parse_next ( input) ?
9981007 } ;
999- cut_err ( ( "\" " , & hashes[ ..] ) )
1000- . context ( lbl ( "closing quote" ) )
1001- . parse_next ( input) ?;
1008+ let closing_quotes = if is_multiline {
1009+ "\" \" \" " . context ( lbl ( "multiline raw string closing quotes" ) )
1010+ } else {
1011+ "\" " . context ( lbl ( "raw string closing quotes" ) )
1012+ } ;
1013+ cut_err ( ( closing_quotes, & hashes[ ..] ) ) . parse_next ( input) ?;
10021014 Ok ( body. map ( KdlValue :: String ) )
10031015}
10041016
@@ -1044,40 +1056,46 @@ mod string_tests {
10441056 #[ test]
10451057 fn multiline_quoted_string ( ) {
10461058 assert_eq ! (
1047- string. parse( new_input( "\" \n foo\n bar\n baz\n \" " ) ) . unwrap( ) ,
1059+ string
1060+ . parse( new_input( "\" \" \" \n foo\n bar\n baz\n \" \" \" " ) )
1061+ . unwrap( ) ,
10481062 Some ( KdlValue :: String ( "foo\n bar\n baz" . into( ) ) )
10491063 ) ;
10501064 assert_eq ! (
10511065 string
1052- . parse( new_input( "\" \n foo\n bar\n baz\n \" " ) )
1066+ . parse( new_input( "\" \" \" \ n foo\n bar\n baz\n \" \" \" " ) )
10531067 . unwrap( ) ,
10541068 Some ( KdlValue :: String ( "foo\n bar\n baz" . into( ) ) )
10551069 ) ;
10561070 assert_eq ! (
1057- string. parse( new_input( "\" \n foo\r \n bar\n baz\n \" " ) ) . unwrap( ) ,
1071+ string
1072+ . parse( new_input( "\" \" \" \n foo\r \n bar\n baz\n \" \" \" " ) )
1073+ . unwrap( ) ,
10581074 Some ( KdlValue :: String ( "foo\n bar\n baz" . into( ) ) )
10591075 ) ;
10601076 assert_eq ! (
10611077 string
1062- . parse( new_input( "\" \n foo\n bar\n baz\n \" " ) )
1078+ . parse( new_input( "\" \" \" \ n foo\n bar\n baz\n \" \" \" " ) )
10631079 . unwrap( ) ,
10641080 Some ( KdlValue :: String ( "foo\n bar\n baz" . into( ) ) )
10651081 ) ;
10661082 assert_eq ! (
10671083 string
1068- . parse( new_input( "\" \n \\ foo\n \\ bar\n \\ baz\n \" " ) )
1084+ . parse( new_input(
1085+ "\" \" \" \n \\ foo\n \\ bar\n \\ baz\n \" \" \" "
1086+ ) )
10691087 . unwrap( ) ,
10701088 Some ( KdlValue :: String ( "foo\n bar\n baz" . into( ) ) )
10711089 ) ;
10721090 assert_eq ! (
10731091 string
1074- . parse( new_input( "\" \n \n string\t \n \" " ) )
1092+ . parse( new_input( "\" \" \" \ n\n string\t \n \" \" \" " ) )
10751093 . unwrap( ) ,
10761094 Some ( KdlValue :: String ( "\n string\t " . into( ) ) ) ,
10771095 "Empty line without any indentation"
10781096 ) ;
10791097 assert ! ( string
1080- . parse( new_input( "\" \n foo\n bar\n baz\n \" " ) )
1098+ . parse( new_input( "\" \" \" \ n foo\n bar\n baz\n \" \" \" " ) )
10811099 . is_err( ) ) ;
10821100 }
10831101
@@ -1092,30 +1110,35 @@ mod string_tests {
10921110 #[ test]
10931111 fn multiline_raw_string ( ) {
10941112 assert_eq ! (
1095- string. parse( new_input( "#\" \n foo\n bar\n baz\n \" #" ) ) . unwrap( ) ,
1113+ string
1114+ . parse( new_input( "#\" \" \" \n foo\n bar\n baz\n \" \" \" #" ) )
1115+ . unwrap( ) ,
10961116 Some ( KdlValue :: String ( "foo\n bar\n baz" . into( ) ) )
10971117 ) ;
10981118 assert_eq ! (
10991119 string
1100- . parse( new_input( "#\" \n foo\r \n bar\n baz\n \" #" ) )
1120+ . parse( new_input( "#\" \" \" \ n foo\r \n bar\n baz\n \" \" \" #" ) )
11011121 . unwrap( ) ,
11021122 Some ( KdlValue :: String ( "foo\n bar\n baz" . into( ) ) )
11031123 ) ;
11041124 assert_eq ! (
11051125 string
1106- . parse( new_input( "##\" \n foo\n bar\n baz\n \" ##" ) )
1126+ . parse( new_input( "##\" \" \" \ n foo\n bar\n baz\n \" \" \" ##" ) )
11071127 . unwrap( ) ,
11081128 Some ( KdlValue :: String ( "foo\n bar\n baz" . into( ) ) )
11091129 ) ;
11101130 assert_eq ! (
11111131 string
1112- . parse( new_input( "#\" \n foo\n \\ nbar\n baz\n \" #" ) )
1132+ . parse( new_input( "#\" \" \" \ n foo\n \\ nbar\n baz\n \" \" \" #" ) )
11131133 . unwrap( ) ,
11141134 Some ( KdlValue :: String ( "foo\n \\ nbar\n baz" . into( ) ) )
11151135 ) ;
11161136 assert ! ( string
1117- . parse( new_input( "#\" \n foo\n bar\n baz\n \" #" ) )
1137+ . parse( new_input( "#\" \" \" \ n foo\n bar\n baz\n \" \" \" #" ) )
11181138 . is_err( ) ) ;
1139+
1140+ assert ! ( string. parse( new_input( "#\" \n foo\n bar\n baz\n \" #" ) ) . is_err( ) ) ;
1141+ assert ! ( string. parse( new_input( "\" \n foo\n bar\n baz\n \" " ) ) . is_err( ) ) ;
11191142 }
11201143
11211144 #[ test]
0 commit comments