@@ -89,3 +89,57 @@ def tokens_to_string(tokens):
8989 # last line
9090 content += line
9191 return content
92+
93+
94+ def unquote (s , is_double_quoted = False ):
95+ s = s .replace ('\\ "' , '"' ).replace ("\\ '" , "'" )
96+ if is_double_quoted :
97+ s = s .replace ('""' , '"' )
98+ else :
99+ s = s .replace ("''" , "'" )
100+ return s
101+
102+
103+ def dump_json (obj ) -> str :
104+ '''
105+ dump dict into json-like string using:
106+ - single quotes for strings
107+ - the same quoting rules as `unquote` function
108+ '''
109+
110+
111+ if isinstance (obj , dict ):
112+ items = []
113+ for k , v in obj .items ():
114+ # keys must be strings in JSON
115+ if not isinstance (k , str ):
116+ k = str (k )
117+ items .append (f'{ dump_json (k )} : { dump_json (v )} ' )
118+ return "{" + ", " .join (items ) + "}"
119+
120+ if isinstance (obj , (list , tuple )):
121+ items = [
122+ dump_json (i ) for i in obj
123+ ]
124+ return "[" + ", " .join (items ) + "]"
125+
126+ if isinstance (obj , str ):
127+ obj = obj .replace ("'" , "''" )
128+ return f"'{ obj } '"
129+
130+ if isinstance (obj , (int , float )):
131+ if obj != obj : # NaN
132+ return "null"
133+ if obj == float ('inf' ):
134+ return "null"
135+ if obj == float ('-inf' ):
136+ return "null"
137+ return str (obj )
138+
139+ if obj is None :
140+ return "null"
141+
142+ if isinstance (obj , bool ):
143+ return "true" if obj else "false"
144+
145+ return dump_json (str (obj ))
0 commit comments