blob: ba1fd357cb17a1032610c93b98eb32d17813ef1c [file] [log] [blame] [edit]
# Copyright 2015 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re
import json
from json5.parser import Parser
def load(fp, **kwargs):
s = fp.read()
return loads(s, **kwargs)
def loads(s, **kwargs):
if not s:
raise ValueError('Empty strings are not legal JSON5')
parser = Parser(s, '<string>')
ast, err = parser.parse()
if not err:
return _walk_ast(ast)
raise ValueError(err)
def _walk_ast(el):
if el == 'None':
return None
if el == 'True':
return True
if el == 'False':
return False
ty, v = el
if ty == 'number':
if v.startswith('0x') or v.startswith('0X'):
return int(v, base=16)
if '.' in v or 'e' in v or 'E' in v:
return float(v)
if 'Infinity' in v:
return float(v.replace('Infinity', 'inf'))
if 'NaN' in v:
return float(v.replace('NaN', 'nan'))
return int(v)
if ty == 'string':
return v
if ty == 'object':
o = {}
for m in v:
k = m[0]
v = _walk_ast(m[1])
o[k] = v
return o
if ty == 'array':
return [_walk_ast(el) for el in v]
raise Exception('unknown el: ' + el)
REPLACE = {
True: 'true',
False: 'false',
None: 'null'
}
notletter = re.compile('\W')
def dumps(data, compact=False, **kwargs):
if not compact:
return json.dumps(data, **kwargs)
t = type(data)
if t is bool or t is None:
return REPLACE[data]
elif t is str:
single = "'" in data
double = '"' in data
if single and double:
return json.dumps(data)
elif single:
return '"' + data + '"'
else:
return "'" + data + "'"
elif t is float or t is int:
return str(data)
elif t is dict:
return '{' + ','.join([
_dumpkey(k) + ':' + dumps(v) for k, v in data.items()
]) + '}'
elif t is list:
return '[' + ','.join([dumps(v) for v in data]) + ']'
else:
return ''
def _dumpkey(k):
if notletter.search(k):
return json.dumps(k)
else:
return str(k)
def dump(obj, fp, **kwargs):
s = dumps(obj, **kwargs)
fp.write(s)