@@ -125,6 +125,7 @@ impl<'a> PathParser<'a> {
125125 self . expect_char ( '[' ) ?;
126126 let segment = match self . peek_char ( ) {
127127 Some ( '"' ) => PathSegment :: Property ( self . parse_json_string ( ) ?) ,
128+ Some ( '\'' ) => PathSegment :: Property ( self . parse_quoted_string ( '\'' ) ?) ,
128129 Some ( ch) if ch. is_ascii_digit ( ) => PathSegment :: Index ( self . parse_index ( ) ?) ,
129130 Some ( ch) => {
130131 return Err ( anyhow ! (
@@ -158,6 +159,61 @@ impl<'a> PathParser<'a> {
158159 Err ( anyhow ! ( "Unclosed string path segment" ) )
159160 }
160161
162+ fn parse_quoted_string ( & mut self , delimiter : char ) -> Result < String > {
163+ self . bump_char ( ) ;
164+
165+ let mut result = String :: new ( ) ;
166+ while let Some ( ch) = self . peek_char ( ) {
167+ self . bump_char ( ) ;
168+ if ch == delimiter {
169+ return Ok ( result) ;
170+ }
171+ if ch == '\\' {
172+ result. push ( self . parse_escape_sequence ( ) ?) ;
173+ } else {
174+ result. push ( ch) ;
175+ }
176+ }
177+
178+ Err ( anyhow ! ( "Unclosed string path segment" ) )
179+ }
180+
181+ fn parse_escape_sequence ( & mut self ) -> Result < char > {
182+ let Some ( ch) = self . peek_char ( ) else {
183+ return Err ( anyhow ! ( "Unclosed escape sequence" ) ) ;
184+ } ;
185+ self . bump_char ( ) ;
186+
187+ match ch {
188+ '"' => Ok ( '"' ) ,
189+ '\'' => Ok ( '\'' ) ,
190+ '\\' => Ok ( '\\' ) ,
191+ '/' => Ok ( '/' ) ,
192+ 'b' => Ok ( '\u{0008}' ) ,
193+ 'f' => Ok ( '\u{000c}' ) ,
194+ 'n' => Ok ( '\n' ) ,
195+ 'r' => Ok ( '\r' ) ,
196+ 't' => Ok ( '\t' ) ,
197+ 'u' => self . parse_unicode_escape ( ) ,
198+ other => Ok ( other) ,
199+ }
200+ }
201+
202+ fn parse_unicode_escape ( & mut self ) -> Result < char > {
203+ let start = self . pos ;
204+ for _ in 0 ..4 {
205+ match self . peek_char ( ) {
206+ Some ( ch) if ch. is_ascii_hexdigit ( ) => self . bump_char ( ) ,
207+ Some ( ch) => return Err ( anyhow ! ( "Invalid unicode escape character '{}'" , ch) ) ,
208+ None => return Err ( anyhow ! ( "Unclosed unicode escape sequence" ) ) ,
209+ }
210+ }
211+
212+ let code = u32:: from_str_radix ( & self . input [ start..self . pos ] , 16 )
213+ . context ( "Failed to parse unicode escape" ) ?;
214+ char:: from_u32 ( code) . ok_or_else ( || anyhow ! ( "Invalid unicode escape code point" ) )
215+ }
216+
161217 fn parse_index ( & mut self ) -> Result < usize > {
162218 let start = self . pos ;
163219 while matches ! ( self . peek_char( ) , Some ( ch) if ch. is_ascii_digit( ) ) {
@@ -220,7 +276,12 @@ fn parse_value(right: &str) -> Result<JsonValue> {
220276 return Err ( anyhow ! ( "Expected assignment to end with ';'" ) ) ;
221277 } ;
222278
223- serde_json:: from_str ( value_src. trim ( ) ) . context ( "Failed to parse gron value as JSON" )
279+ let value_src = value_src. trim ( ) ;
280+ if value_src. starts_with ( '\'' ) {
281+ return parse_single_quoted_value ( value_src) ;
282+ }
283+
284+ serde_json:: from_str ( value_src) . context ( "Failed to parse gron value as JSON" )
224285}
225286
226287fn strip_trailing_semicolon ( right : & str ) -> Option < & str > {
@@ -234,7 +295,7 @@ fn strip_trailing_semicolon(right: &str) -> Option<&str> {
234295 Some ( _) if ch == '\\' => escaped = true ,
235296 Some ( delimiter) if ch == delimiter => string_delimiter = None ,
236297 Some ( _) => { }
237- None if ch == '"' => string_delimiter = Some ( ch) ,
298+ None if ch == '"' || ch == '\'' => string_delimiter = Some ( ch) ,
238299 None if ch == ';' => semicolon = Some ( idx) ,
239300 None if !ch. is_whitespace ( ) && semicolon. is_some ( ) => return None ,
240301 None => { }
@@ -244,6 +305,15 @@ fn strip_trailing_semicolon(right: &str) -> Option<&str> {
244305 semicolon. map ( |idx| & right[ ..idx] )
245306}
246307
308+ fn parse_single_quoted_value ( value_src : & str ) -> Result < JsonValue > {
309+ let mut parser = PathParser :: new ( value_src) ;
310+ let value = parser. parse_quoted_string ( '\'' ) ?;
311+ if !parser. input [ parser. pos ..] . trim ( ) . is_empty ( ) {
312+ return Err ( anyhow ! ( "Unexpected characters after string value" ) ) ;
313+ }
314+ Ok ( JsonValue :: String ( value) )
315+ }
316+
247317fn set_value_at_path ( root : & mut JsonValue , path : & [ PathSegment ] , value : JsonValue ) -> Result < ( ) > {
248318 let mut cur = root;
249319
0 commit comments