|  | @@ -1,109 +0,0 @@
 | 
	
		
			
				|  |  | -"""trivialjson (https://github.com/phihag/trivialjson)"""
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import re
 | 
	
		
			
				|  |  | -def loads(s):
 | 
	
		
			
				|  |  | -	s = s.decode('UTF-8')
 | 
	
		
			
				|  |  | -	def raiseError(msg, i):
 | 
	
		
			
				|  |  | -		raise ValueError(msg + ' at position ' + str(i) + ' of ' + repr(s) + ': ' + repr(s[i:]))
 | 
	
		
			
				|  |  | -	def skipSpace(i, expectMore=True):
 | 
	
		
			
				|  |  | -		while i < len(s) and s[i] in ' \t\r\n':
 | 
	
		
			
				|  |  | -			i += 1
 | 
	
		
			
				|  |  | -		if expectMore:
 | 
	
		
			
				|  |  | -			if i >= len(s):
 | 
	
		
			
				|  |  | -				raiseError('Premature end', i)
 | 
	
		
			
				|  |  | -		return i
 | 
	
		
			
				|  |  | -	def decodeEscape(match):
 | 
	
		
			
				|  |  | -		esc = match.group(1)
 | 
	
		
			
				|  |  | -		_STATIC = {
 | 
	
		
			
				|  |  | -			'"': '"',
 | 
	
		
			
				|  |  | -			'\\': '\\',
 | 
	
		
			
				|  |  | -			'/': '/',
 | 
	
		
			
				|  |  | -			'b': unichr(0x8),
 | 
	
		
			
				|  |  | -			'f': unichr(0xc),
 | 
	
		
			
				|  |  | -			'n': '\n',
 | 
	
		
			
				|  |  | -			'r': '\r',
 | 
	
		
			
				|  |  | -			't': '\t',
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		if esc in _STATIC:
 | 
	
		
			
				|  |  | -			return _STATIC[esc]
 | 
	
		
			
				|  |  | -		if esc[0] == 'u':
 | 
	
		
			
				|  |  | -			if len(esc) == 1+4:
 | 
	
		
			
				|  |  | -				return unichr(int(esc[1:5], 16))
 | 
	
		
			
				|  |  | -			if len(esc) == 5+6 and esc[5:7] == '\\u':
 | 
	
		
			
				|  |  | -				hi = int(esc[1:5], 16)
 | 
	
		
			
				|  |  | -				low = int(esc[7:11], 16)
 | 
	
		
			
				|  |  | -				return unichr((hi - 0xd800) * 0x400 + low - 0xdc00 + 0x10000)
 | 
	
		
			
				|  |  | -		raise ValueError('Unknown escape ' + str(esc))
 | 
	
		
			
				|  |  | -	def parseString(i):
 | 
	
		
			
				|  |  | -		i += 1
 | 
	
		
			
				|  |  | -		e = i
 | 
	
		
			
				|  |  | -		while True:
 | 
	
		
			
				|  |  | -			e = s.index('"', e)
 | 
	
		
			
				|  |  | -			bslashes = 0
 | 
	
		
			
				|  |  | -			while s[e-bslashes-1] == '\\':
 | 
	
		
			
				|  |  | -				bslashes += 1
 | 
	
		
			
				|  |  | -			if bslashes % 2 == 1:
 | 
	
		
			
				|  |  | -				e += 1
 | 
	
		
			
				|  |  | -				continue
 | 
	
		
			
				|  |  | -			break
 | 
	
		
			
				|  |  | -		rexp = re.compile(r'\\(u[dD][89aAbB][0-9a-fA-F]{2}\\u[0-9a-fA-F]{4}|u[0-9a-fA-F]{4}|.|$)')
 | 
	
		
			
				|  |  | -		stri = rexp.sub(decodeEscape, s[i:e])
 | 
	
		
			
				|  |  | -		return (e+1,stri)
 | 
	
		
			
				|  |  | -	def parseObj(i):
 | 
	
		
			
				|  |  | -		i += 1
 | 
	
		
			
				|  |  | -		res = {}
 | 
	
		
			
				|  |  | -		i = skipSpace(i)
 | 
	
		
			
				|  |  | -		if s[i] == '}': # Empty dictionary
 | 
	
		
			
				|  |  | -			return (i+1,res)
 | 
	
		
			
				|  |  | -		while True:
 | 
	
		
			
				|  |  | -			if s[i] != '"':
 | 
	
		
			
				|  |  | -				raiseError('Expected a string object key', i)
 | 
	
		
			
				|  |  | -			i,key = parseString(i)
 | 
	
		
			
				|  |  | -			i = skipSpace(i)
 | 
	
		
			
				|  |  | -			if i >= len(s) or s[i] != ':':
 | 
	
		
			
				|  |  | -				raiseError('Expected a colon', i)
 | 
	
		
			
				|  |  | -			i,val = parse(i+1)
 | 
	
		
			
				|  |  | -			res[key] = val
 | 
	
		
			
				|  |  | -			i = skipSpace(i)
 | 
	
		
			
				|  |  | -			if s[i] == '}':
 | 
	
		
			
				|  |  | -				return (i+1, res)
 | 
	
		
			
				|  |  | -			if s[i] != ',':
 | 
	
		
			
				|  |  | -				raiseError('Expected comma or closing curly brace', i)
 | 
	
		
			
				|  |  | -			i = skipSpace(i+1)
 | 
	
		
			
				|  |  | -	def parseArray(i):
 | 
	
		
			
				|  |  | -		res = []
 | 
	
		
			
				|  |  | -		i = skipSpace(i+1)
 | 
	
		
			
				|  |  | -		if s[i] == ']': # Empty array
 | 
	
		
			
				|  |  | -			return (i+1,res)
 | 
	
		
			
				|  |  | -		while True:
 | 
	
		
			
				|  |  | -			i,val = parse(i)
 | 
	
		
			
				|  |  | -			res.append(val)
 | 
	
		
			
				|  |  | -			i = skipSpace(i) # Raise exception if premature end
 | 
	
		
			
				|  |  | -			if s[i] == ']':
 | 
	
		
			
				|  |  | -				return (i+1, res)
 | 
	
		
			
				|  |  | -			if s[i] != ',':
 | 
	
		
			
				|  |  | -				raiseError('Expected a comma or closing bracket', i)
 | 
	
		
			
				|  |  | -			i = skipSpace(i+1)
 | 
	
		
			
				|  |  | -	def parseDiscrete(i):
 | 
	
		
			
				|  |  | -		for k,v in {'true': True, 'false': False, 'null': None}.items():
 | 
	
		
			
				|  |  | -			if s.startswith(k, i):
 | 
	
		
			
				|  |  | -				return (i+len(k), v)
 | 
	
		
			
				|  |  | -		raiseError('Not a boolean (or null)', i)
 | 
	
		
			
				|  |  | -	def parseNumber(i):
 | 
	
		
			
				|  |  | -		mobj = re.match('^(-?(0|[1-9][0-9]*)(\.[0-9]*)?([eE][+-]?[0-9]+)?)', s[i:])
 | 
	
		
			
				|  |  | -		if mobj is None:
 | 
	
		
			
				|  |  | -			raiseError('Not a number', i)
 | 
	
		
			
				|  |  | -		nums = mobj.group(1)
 | 
	
		
			
				|  |  | -		if '.' in nums or 'e' in nums or 'E' in nums:
 | 
	
		
			
				|  |  | -			return (i+len(nums), float(nums))
 | 
	
		
			
				|  |  | -		return (i+len(nums), int(nums))
 | 
	
		
			
				|  |  | -	CHARMAP = {'{': parseObj, '[': parseArray, '"': parseString, 't': parseDiscrete, 'f': parseDiscrete, 'n': parseDiscrete}
 | 
	
		
			
				|  |  | -	def parse(i):
 | 
	
		
			
				|  |  | -		i = skipSpace(i)
 | 
	
		
			
				|  |  | -		i,res = CHARMAP.get(s[i], parseNumber)(i)
 | 
	
		
			
				|  |  | -		i = skipSpace(i, False)
 | 
	
		
			
				|  |  | -		return (i,res)
 | 
	
		
			
				|  |  | -	i,res = parse(0)
 | 
	
		
			
				|  |  | -	if i < len(s):
 | 
	
		
			
				|  |  | -		raise ValueError('Extra data at end of input (index ' + str(i) + ' of ' + repr(s) + ': ' + repr(s[i:]) + ')')
 | 
	
		
			
				|  |  | -	return res
 |