@@ -70,11 +70,9 @@ impl InterpolableFragment {
7070 s. insert_str ( 0 , "\" '" ) ;
7171 }
7272
73- let unescaped = count_single_quotes ( s , & mut in_double_quotes) ;
73+ let single_quote_open = scan_quote_state ( s , & mut in_single_quotes , & mut in_double_quotes) ;
7474
75- // If this chunk has an odd number of unescaped quotes, it toggles the region.
76- if unescaped % 2 == 1 {
77- in_single_quotes = !in_single_quotes;
75+ if single_quote_open {
7876 // Close the chunk locally so each piece is balanced.
7977 s. push_str ( "'\" " ) ;
8078 }
@@ -103,30 +101,32 @@ impl InterpolableFragment {
103101 }
104102}
105103
106- /// Count single quotes that are NOT escaped by an odd number of preceding backslashes.
107- fn count_single_quotes ( s : & str , in_double_quotes : & mut bool ) -> usize {
108- let mut count = 0usize ;
109- let mut backslashes = 0usize ;
104+ /// Scans a string to determine the quoting state, updating the state flags.
105+ /// Returns `true` if the single-quote state was toggled.
106+ fn scan_quote_state ( s : & str , in_single_quotes : & mut bool , in_double_quotes : & mut bool ) -> bool {
107+ let initial_in_single_quotes = * in_single_quotes;
108+ let mut backslashes = 0 ;
110109
111110 for b in s. bytes ( ) {
112111 match b {
113112 b'\\' => backslashes += 1 ,
114113 b'"' => {
115- if backslashes % 2 == 0 {
114+ if ! * in_single_quotes && backslashes % 2 == 0 {
116115 * in_double_quotes = !* in_double_quotes;
117116 }
118117 backslashes = 0 ;
119118 }
120119 b'\'' => {
121120 if !* in_double_quotes && backslashes % 2 == 0 {
122- count += 1 ;
121+ * in_single_quotes = ! * in_single_quotes ;
123122 }
124123 backslashes = 0 ;
125124 }
126125 _ => backslashes = 0 ,
127126 }
128127 }
129- count
128+
129+ initial_in_single_quotes != * in_single_quotes
130130}
131131
132132impl FragmentRenderable for InterpolableFragment {
@@ -186,34 +186,47 @@ mod tests {
186186 }
187187
188188 #[ test]
189- fn test_count_unescaped_single_quotes ( ) {
190- let mut in_dq;
191- in_dq = false ; assert_eq ! ( count_single_quotes( r#"foo"# , & mut in_dq) , 0 ) ;
192- in_dq = false ; assert_eq ! ( count_single_quotes( r#"foo\'bar"# , & mut in_dq) , 0 ) ;
193- in_dq = false ; assert_eq ! ( count_single_quotes( r#"foo'bar"# , & mut in_dq) , 1 ) ;
189+ fn test_toggles_single_quote_state ( ) {
190+ let mut dq = false ;
191+ let mut sq = false ;
192+ scan_quote_state ( r#"foo"# , & mut sq, & mut dq) ;
193+ scan_quote_state ( r#"foo\'bar"# , & mut sq, & mut dq) ;
194+ scan_quote_state ( r#"foo'bar"# , & mut sq, & mut dq) ;
194195 // even number of backslashes before quote -> not escaped
195- in_dq = false ; assert_eq ! ( count_single_quotes( r#"foo\\\\'bar"# , & mut in_dq) , 1 ) ;
196- in_dq = false ; assert_eq ! ( count_single_quotes( r#"'"# , & mut in_dq) , 1 ) ;
197- in_dq = false ; assert_eq ! ( count_single_quotes( r#"'\"'"# , & mut in_dq) , 2 ) ;
198- in_dq = false ; assert_eq ! ( count_single_quotes( r#"'''"# , & mut in_dq) , 3 ) ;
199- in_dq = false ; assert_eq ! ( count_single_quotes( r#""'""# , & mut in_dq) , 0 ) ;
200-
201- in_dq = false ;
202- assert_eq ! ( count_single_quotes( r#"'""# , & mut in_dq) , 1 ) ;
203- assert ! ( in_dq) ;
204- assert_eq ! ( count_single_quotes( r#"'""# , & mut in_dq) , 0 ) ;
205- assert ! ( !in_dq) ;
206- assert_eq ! ( count_single_quotes( r#"\"'\""# , & mut in_dq) , 1 ) ;
207- assert ! ( !in_dq) ;
208- assert_eq ! ( count_single_quotes( r#"""# , & mut in_dq) , 0 ) ;
209- assert ! ( in_dq) ;
210- assert_eq ! ( count_single_quotes( r#"'"# , & mut in_dq) , 0 ) ;
211- assert ! ( in_dq) ;
212- assert_eq ! ( count_single_quotes( r#"\'"# , & mut in_dq) , 0 ) ;
213- assert ! ( in_dq) ;
214- assert_eq ! ( count_single_quotes( r#"\""# , & mut in_dq) , 0 ) ;
215- assert ! ( in_dq) ;
216- assert_eq ! ( count_single_quotes( r#"""# , & mut in_dq) , 0 ) ;
217- assert ! ( !in_dq) ;
196+ scan_quote_state ( r#"foo\\\\'bar"# , & mut sq, & mut dq) ;
197+ scan_quote_state ( r#"'"# , & mut sq, & mut dq) ;
198+ scan_quote_state ( r#"'\"'"# , & mut sq, & mut dq) ;
199+ scan_quote_state ( r#"'''"# , & mut sq, & mut dq) ;
200+ scan_quote_state ( r#""'""# , & mut sq, & mut dq) ;
201+
202+ sq = false ;
203+ dq = false ;
204+ scan_quote_state ( r#" '" "# , & mut sq, & mut dq) ;
205+ assert ! ( sq) ;
206+ assert ! ( !dq) ;
207+ scan_quote_state ( r#" '" "# , & mut sq, & mut dq) ;
208+ assert ! ( !sq) ;
209+ assert ! ( dq) ;
210+ scan_quote_state ( r#" \"'\" "# , & mut sq, & mut dq) ;
211+ assert ! ( !sq) ;
212+ assert ! ( dq) ;
213+ scan_quote_state ( r#" " "# , & mut sq, & mut dq) ;
214+ assert ! ( !sq) ;
215+ assert ! ( !dq) ;
216+ scan_quote_state ( r#" ' "# , & mut sq, & mut dq) ;
217+ assert ! ( sq) ;
218+ assert ! ( !dq) ;
219+ scan_quote_state ( r#" \' "# , & mut sq, & mut dq) ;
220+ assert ! ( sq) ;
221+ assert ! ( !dq) ;
222+ scan_quote_state ( r#" \" "# , & mut sq, & mut dq) ;
223+ assert ! ( sq) ;
224+ assert ! ( !dq) ;
225+ scan_quote_state ( r#" " "# , & mut sq, & mut dq) ;
226+ assert ! ( sq) ;
227+ assert ! ( !dq) ;
228+ scan_quote_state ( r#" '"' "# , & mut sq, & mut dq) ;
229+ assert ! ( !sq) ;
230+ assert ! ( dq) ;
218231 }
219232}
0 commit comments