mirror of https://github.com/rxi/json.lua.git
				
				
				
			Merge 62e3d71808 into dbf4b2dd2e
				
					
				
			
						commit
						b907c78d2c
					
				|  | @ -1 +0,0 @@ | ||||||
| github: rxi |  | ||||||
							
								
								
									
										3
									
								
								LICENSE
								
								
								
								
							
							
						
						
									
										3
									
								
								LICENSE
								
								
								
								
							|  | @ -1,5 +1,4 @@ | ||||||
| Copyright (c) 2020 rxi | Copyright (c) 2020 rxi (v0.1.2) edit by DarhangeR (v0.1.4) | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||||
| this software and associated documentation files (the "Software"), to deal in | this software and associated documentation files (the "Software"), to deal in | ||||||
|  |  | ||||||
							
								
								
									
										257
									
								
								json.lua
								
								
								
								
							
							
						
						
									
										257
									
								
								json.lua
								
								
								
								
							|  | @ -1,7 +1,7 @@ | ||||||
| -- | -- | ||||||
| -- json.lua | -- json.lua | ||||||
| -- | -- | ||||||
| -- Copyright (c) 2020 rxi | -- Copyright (c) 2020 rxi (v0.1.2) edit by DarhangeR (v0.1.4) | ||||||
| -- | -- | ||||||
| -- Permission is hereby granted, free of charge, to any person obtaining a copy of | -- Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||||
| -- this software and associated documentation files (the "Software"), to deal in | -- this software and associated documentation files (the "Software"), to deal in | ||||||
|  | @ -22,7 +22,8 @@ | ||||||
| -- SOFTWARE. | -- SOFTWARE. | ||||||
| -- | -- | ||||||
| 
 | 
 | ||||||
| local json = { _version = "0.1.2" } | local pairs, string_format, error, rawget, next, string_char, type, ipairs, table_concat, tostring, select, tonumber = pairs, string.format, error, rawget, next, string.char, type, ipairs, table.concat, tostring, select, tonumber | ||||||
|  | local json = { _version = "0.1.4" }; | ||||||
| 
 | 
 | ||||||
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||||||
| -- Encode | -- Encode | ||||||
|  | @ -38,36 +39,28 @@ local escape_char_map = { | ||||||
|   [ "\n" ] = "n", |   [ "\n" ] = "n", | ||||||
|   [ "\r" ] = "r", |   [ "\r" ] = "r", | ||||||
|   [ "\t" ] = "t", |   [ "\t" ] = "t", | ||||||
| } | }; | ||||||
| 
 | 
 | ||||||
| local escape_char_map_inv = { [ "/" ] = "/" } | local escape_char_map_inv = { [ "/" ] = "/" } | ||||||
| for k, v in pairs(escape_char_map) do | for k, v in pairs(escape_char_map) do | ||||||
|   escape_char_map_inv[v] = k | 	escape_char_map_inv[v] = k; | ||||||
| end | end; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| local function escape_char(c) | local function escape_char(c) | ||||||
|   return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) | 	return "\\" .. (escape_char_map[c] or string_format("u%04x", c:byte())); | ||||||
| end | end; | ||||||
| 
 | 
 | ||||||
|  | local function encode_nil(rope) | ||||||
|  | 	rope[#rope + 1] = "null" | ||||||
|  | end; | ||||||
| 
 | 
 | ||||||
| local function encode_nil(val) | local function encode_table(rope, val, stack) | ||||||
|   return "null" |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| local function encode_table(val, stack) |  | ||||||
|   local res = {} |  | ||||||
|   stack = stack or {} |  | ||||||
| 
 |  | ||||||
| 	-- Circular reference? | 	-- Circular reference? | ||||||
| 	if stack[val] then error("circular reference") end | 	if stack[val] then error("circular reference") end | ||||||
| 
 |  | ||||||
| 		stack[val] = true | 		stack[val] = true | ||||||
| 
 |  | ||||||
| 	if rawget(val, 1) ~= nil or next(val) == nil then | 	if rawget(val, 1) ~= nil or next(val) == nil then | ||||||
| 		-- Treat as array -- check keys are valid and it is not sparse | 		-- Treat as array -- check keys are valid and it is not sparse | ||||||
|     local n = 0 | 		local n = 0; | ||||||
| 		for k in pairs(val) do | 		for k in pairs(val) do | ||||||
| 			if type(k) ~= "number" then | 			if type(k) ~= "number" then | ||||||
| 				error("invalid table: mixed or invalid key types") | 				error("invalid table: mixed or invalid key types") | ||||||
|  | @ -78,63 +71,77 @@ local function encode_table(val, stack) | ||||||
| 			error("invalid table: sparse array") | 			error("invalid table: sparse array") | ||||||
| 		end | 		end | ||||||
| 		-- Encode | 		-- Encode | ||||||
|  | 		rope[#rope + 1] = "[" | ||||||
| 		for i, v in ipairs(val) do | 		for i, v in ipairs(val) do | ||||||
|       table.insert(res, encode(v, stack)) | 		if i > 1 then | ||||||
|  | 			rope[#rope + 1] = "," | ||||||
| 		end | 		end | ||||||
|     stack[val] = nil | 			encode(rope, v, stack) | ||||||
|     return "[" .. table.concat(res, ",") .. "]" | 		end | ||||||
| 
 | 		rope[#rope + 1] = "]" | ||||||
| 	else | 	else | ||||||
| 		-- Treat as an object | 		-- Treat as an object | ||||||
|  | 		rope[#rope + 1] = "{" | ||||||
|  | 		local first = true; | ||||||
| 		for k, v in pairs(val) do | 		for k, v in pairs(val) do | ||||||
| 			if type(k) ~= "string" then | 			if type(k) ~= "string" then | ||||||
| 				error("invalid table: mixed or invalid key types") | 				error("invalid table: mixed or invalid key types") | ||||||
| 			end | 			end | ||||||
|       table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) | 			if not first then | ||||||
|  | 				rope[#rope + 1] = "," | ||||||
|  | 			end | ||||||
|  | 			encode(rope, k, stack) | ||||||
|  | 			rope[#rope + 1] = ":" | ||||||
|  | 			encode(rope, v, stack) | ||||||
|  | 			first = false | ||||||
|  | 		end | ||||||
|  | 		rope[#rope + 1] = "}" | ||||||
| 	end | 	end | ||||||
| 	stack[val] = nil | 	stack[val] = nil | ||||||
|     return "{" .. table.concat(res, ",") .. "}" | end; | ||||||
|   end |  | ||||||
| end |  | ||||||
| 
 | 
 | ||||||
|  | local function encode_string(rope, val) | ||||||
|  | 	rope[#rope + 1] = '"' | ||||||
|  | 	rope[#rope + 1] = val:gsub('[%z\1-\31\\"]', escape_char) | ||||||
|  | 	rope[#rope + 1] = '"' | ||||||
|  | end; | ||||||
| 
 | 
 | ||||||
| local function encode_string(val) | local function encode_number(rope, val) | ||||||
|   return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| local function encode_number(val) |  | ||||||
| 	-- Check for NaN, -inf and inf | 	-- Check for NaN, -inf and inf | ||||||
| 	if val ~= val or val <= -math.huge or val >= math.huge then | 	if val ~= val or val <= -math.huge or val >= math.huge then | ||||||
| 		error("unexpected number value '" .. tostring(val) .. "'") | 		error("unexpected number value '" .. tostring(val) .. "'") | ||||||
| 	end | 	end | ||||||
|   return string.format("%.14g", val) | 	-- See www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF | ||||||
| end | 	-- 17 digits suffice to losslessly represent 64-bit IEEE754 floats | ||||||
|  | 	rope[#rope + 1] = ("%.17g"):format(val) | ||||||
|  | end; | ||||||
| 
 | 
 | ||||||
|  | local function encode_boolean(rope, val) | ||||||
|  | 	rope[#rope + 1] = val and "true" or "false" | ||||||
|  | end; | ||||||
| 
 | 
 | ||||||
| local type_func_map = { | local type_func_map = { | ||||||
|   [ "nil"     ] = encode_nil, |   [ "nil"     ] = encode_nil, | ||||||
|   [ "table"   ] = encode_table, |   [ "table"   ] = encode_table, | ||||||
|   [ "string"  ] = encode_string, |   [ "string"  ] = encode_string, | ||||||
|   [ "number"  ] = encode_number, |   [ "number"  ] = encode_number, | ||||||
|   [ "boolean" ] = tostring, |   [ "boolean" ] = encode_boolean, | ||||||
| } | }; | ||||||
| 
 | 
 | ||||||
| 
 | function encode(rope, val, stack) | ||||||
| encode = function(val, stack) |  | ||||||
| 	local t = type(val) | 	local t = type(val) | ||||||
|   local f = type_func_map[t] | 	local encoder = type_func_map[t] | ||||||
|   if f then | 	if encoder then | ||||||
|     return f(val, stack) | 		return encoder(rope, val, stack) | ||||||
| 	end | 	end | ||||||
| 	error("unexpected type '" .. t .. "'") | 	error("unexpected type '" .. t .. "'") | ||||||
| end | end; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| function json.encode(val) | function json.encode(val) | ||||||
|   return ( encode(val) ) | 	local rope = {} | ||||||
| end | 	encode(rope, val, {}) | ||||||
| 
 | 	return table_concat(rope); | ||||||
|  | end; | ||||||
| 
 | 
 | ||||||
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||||||
| -- Decode | -- Decode | ||||||
|  | @ -143,24 +150,23 @@ end | ||||||
| local parse | local parse | ||||||
| 
 | 
 | ||||||
| local function create_set(...) | local function create_set(...) | ||||||
|   local res = {} | 	local res = {}; | ||||||
| 	for i = 1, select("#", ...) do | 	for i = 1, select("#", ...) do | ||||||
| 		res[ select(i, ...) ] = true | 		res[ select(i, ...) ] = true | ||||||
| 	end | 	end | ||||||
|   return res | 	return res; | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local space_chars   = create_set(" ", "\t", "\r", "\n") | local space_chars   = create_set(" ", "\t", "\r", "\n"); | ||||||
| local delim_chars   = create_set(" ", "\t", "\r", "\n", "]", "}", ",") | local delim_chars   = create_set(" ", "\t", "\r", "\n", "]", "}", ","); | ||||||
| local escape_chars  = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") | local escape_chars  = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u"); | ||||||
| local literals      = create_set("true", "false", "null") | local literals      = create_set("true", "false", "null"); | ||||||
| 
 | 
 | ||||||
| local literal_map = { | local literal_map = { | ||||||
|   [ "true"  ] = true, |   [ "true"  ] = true, | ||||||
|   [ "false" ] = false, |   [ "false" ] = false, | ||||||
|   [ "null"  ] = nil, |   [ "null"  ] = nil, | ||||||
| } | }; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| local function next_char(str, idx, set, negate) | local function next_char(str, idx, set, negate) | ||||||
| 	for i = idx, #str do | 	for i = idx, #str do | ||||||
|  | @ -168,9 +174,8 @@ local function next_char(str, idx, set, negate) | ||||||
| 			return i | 			return i | ||||||
| 		end | 		end | ||||||
| 	end | 	end | ||||||
|   return #str + 1 | 	return #str + 1; | ||||||
| end | end; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| local function decode_error(str, idx, msg) | local function decode_error(str, idx, msg) | ||||||
| 	local line_count = 1 | 	local line_count = 1 | ||||||
|  | @ -182,90 +187,81 @@ local function decode_error(str, idx, msg) | ||||||
| 			col_count = 1 | 			col_count = 1 | ||||||
| 		end | 		end | ||||||
| 	end | 	end | ||||||
|   error( string.format("%s at line %d col %d", msg, line_count, col_count) ) | 	error(string_format("%s at line %d col %d", msg, line_count, col_count)) | ||||||
| end | end; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| local function codepoint_to_utf8(n) | local function codepoint_to_utf8(n) | ||||||
| 	-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa | 	-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa | ||||||
|   local f = math.floor | 	local f = math.floor; | ||||||
| 	if n <= 0x7f then | 	if n <= 0x7f then | ||||||
|     return string.char(n) | 		return string_char(n) | ||||||
| elseif n <= 0x7ff then | elseif n <= 0x7ff then | ||||||
|     return string.char(f(n / 64) + 192, n % 64 + 128) | 		return string_char(f(n / 64) + 192, n % 64 + 128) | ||||||
| elseif n <= 0xffff then | elseif n <= 0xffff then | ||||||
|     return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) | 		return string_char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) | ||||||
| elseif n <= 0x10ffff then | elseif n <= 0x10ffff then | ||||||
|     return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, | 		return string_char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, | ||||||
|         f(n % 4096 / 64) + 128, n % 64 + 128) |         f(n % 4096 / 64) + 128, n % 64 + 128) | ||||||
| 	end | 	end | ||||||
|   error( string.format("invalid unicode codepoint '%x'", n) ) | 	error( string_format("invalid unicode codepoint '%x'", n) ) | ||||||
| end | end; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| local function parse_unicode_escape(s) | local function parse_unicode_escape(s) | ||||||
|   local n1 = tonumber( s:sub(1, 4),  16 ) | 	local n1 = tonumber(s:sub(1, 4), 16); | ||||||
|   local n2 = tonumber( s:sub(7, 10), 16 ) | 	local n2 = tonumber(s:sub(7, 10), 16); | ||||||
| 	-- Surrogate pair? | 	-- Surrogate pair? | ||||||
| 	if n2 then | 	if n2 then | ||||||
|     return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) | 		return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000); | ||||||
| 	else | 	else | ||||||
|     return codepoint_to_utf8(n1) | 		return codepoint_to_utf8(n1); | ||||||
| 	end | 	end | ||||||
| end | end; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| local function parse_string(str, i) | local function parse_string(str, i) | ||||||
|   local res = "" | 	local res = {}; | ||||||
|   local j = i + 1 | 	local j = i + 1; | ||||||
|   local k = j | 	local k = j; | ||||||
| 
 | 
 | ||||||
| 	while j <= #str do | 	while j <= #str do | ||||||
|     local x = str:byte(j) | 		local x = str:byte(j); | ||||||
| 
 |  | ||||||
| 		if x < 32 then | 		if x < 32 then | ||||||
| 			decode_error(str, j, "control character in string") | 			decode_error(str, j, "control character in string") | ||||||
| 
 |  | ||||||
|     elseif x == 92 then -- `\`: Escape |     elseif x == 92 then -- `\`: Escape | ||||||
|       res = res .. str:sub(k, j - 1) | 			res[#res + 1] = str:sub(k, j - 1) | ||||||
| 			j = j + 1 | 			j = j + 1 | ||||||
| 			local c = str:sub(j, j) | 			local c = str:sub(j, j) | ||||||
| 			if c == "u" then | 			if c == "u" then | ||||||
| 				local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) | 				local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) | ||||||
| 				or str:match("^%x%x%x%x", j + 1) | 				or str:match("^%x%x%x%x", j + 1) | ||||||
| 				or decode_error(str, j - 1, "invalid unicode escape in string") | 				or decode_error(str, j - 1, "invalid unicode escape in string") | ||||||
|         res = res .. parse_unicode_escape(hex) | 				res[#res + 1] = parse_unicode_escape(hex) | ||||||
| 				j = j + #hex | 				j = j + #hex | ||||||
| 			else | 			else | ||||||
| 				if not escape_chars[c] then | 				if not escape_chars[c] then | ||||||
| 					decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") | 					decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") | ||||||
| 				end | 				end | ||||||
|         res = res .. escape_char_map_inv[c] | 				res[#res + 1] = escape_char_map_inv[c] | ||||||
| 			end | 			end | ||||||
| 			k = j + 1 | 			k = j + 1 | ||||||
| 
 |  | ||||||
| 	elseif x == 34 then -- `"`: End of string | 	elseif x == 34 then -- `"`: End of string | ||||||
|       res = res .. str:sub(k, j - 1) | 			res[#res + 1] = str:sub(k, j - 1) | ||||||
|       return res, j + 1 | 			return table_concat(res), j + 1 | ||||||
| 		end | 		end | ||||||
| 
 |  | ||||||
| 		j = j + 1 | 		j = j + 1 | ||||||
| 	end | 	end | ||||||
| 
 |  | ||||||
| 	decode_error(str, i, "expected closing quote for string") | 	decode_error(str, i, "expected closing quote for string") | ||||||
| end | 	return table_concat(res); | ||||||
| 
 | end; | ||||||
| 
 | 
 | ||||||
| local function parse_number(str, i) | local function parse_number(str, i) | ||||||
|   local x = next_char(str, i, delim_chars) | 	local x = next_char(str, i, delim_chars); | ||||||
|   local s = str:sub(i, x - 1) | 	local s = str:sub(i, x - 1); | ||||||
|   local n = tonumber(s) | 	local n = tonumber(s); | ||||||
| 	if not n then | 	if not n then | ||||||
| 		decode_error(str, i, "invalid number '" .. s .. "'") | 		decode_error(str, i, "invalid number '" .. s .. "'") | ||||||
| 	end | 	end | ||||||
|   return n, x | 	return n, x; | ||||||
| end | end; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| local function parse_literal(str, i) | local function parse_literal(str, i) | ||||||
| 	local x = next_char(str, i, delim_chars) | 	local x = next_char(str, i, delim_chars) | ||||||
|  | @ -273,21 +269,20 @@ local function parse_literal(str, i) | ||||||
| 	if not literals[word] then | 	if not literals[word] then | ||||||
| 		decode_error(str, i, "invalid literal '" .. word .. "'") | 		decode_error(str, i, "invalid literal '" .. word .. "'") | ||||||
| 	end | 	end | ||||||
|   return literal_map[word], x | 	return literal_map[word], x; | ||||||
| end | end; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| local function parse_array(str, i) | local function parse_array(str, i) | ||||||
|   local res = {} | 	local res = {}; | ||||||
|   local n = 1 | 	local n = 1; | ||||||
| 	i = i + 1 | 	i = i + 1 | ||||||
| 	while 1 do | 	while 1 do | ||||||
|     local x | 		local x; | ||||||
| 		i = next_char(str, i, space_chars, true) | 		i = next_char(str, i, space_chars, true) | ||||||
| 		-- Empty / end of array? | 		-- Empty / end of array? | ||||||
| 		if str:sub(i, i) == "]" then | 		if str:sub(i, i) == "]" then | ||||||
| 			i = i + 1 | 			i = i + 1 | ||||||
|       break | 			break; | ||||||
| 		end | 		end | ||||||
| 		-- Read token | 		-- Read token | ||||||
| 		x, i = parse(str, i) | 		x, i = parse(str, i) | ||||||
|  | @ -295,25 +290,28 @@ local function parse_array(str, i) | ||||||
| 		n = n + 1 | 		n = n + 1 | ||||||
| 		-- Next token | 		-- Next token | ||||||
| 		i = next_char(str, i, space_chars, true) | 		i = next_char(str, i, space_chars, true) | ||||||
|     local chr = str:sub(i, i) | 		local chr = str:sub(i, i); | ||||||
| 		i = i + 1 | 		i = i + 1 | ||||||
|     if chr == "]" then break end | 		if chr == "]" then  | ||||||
|     if chr ~= "," then decode_error(str, i, "expected ']' or ','") end | 			break;  | ||||||
| 		end | 		end | ||||||
|   return res, i | 		if chr ~= "," then  | ||||||
|  | 			decode_error(str, i, "expected ']' or ','")  | ||||||
| 		end | 		end | ||||||
| 
 | 	end | ||||||
|  | 	return res, i; | ||||||
|  | end; | ||||||
| 
 | 
 | ||||||
| local function parse_object(str, i) | local function parse_object(str, i) | ||||||
|   local res = {} | 	local res = {}; | ||||||
| 	i = i + 1 | 	i = i + 1 | ||||||
| 	while 1 do | 	while 1 do | ||||||
|     local key, val | 		local key, val; | ||||||
| 		i = next_char(str, i, space_chars, true) | 		i = next_char(str, i, space_chars, true) | ||||||
| 		-- Empty / end of object? | 		-- Empty / end of object? | ||||||
| 		if str:sub(i, i) == "}" then | 		if str:sub(i, i) == "}" then | ||||||
| 			i = i + 1 | 			i = i + 1 | ||||||
|       break | 			break; | ||||||
| 		end | 		end | ||||||
| 		-- Read key | 		-- Read key | ||||||
| 		if str:sub(i, i) ~= '"' then | 		if str:sub(i, i) ~= '"' then | ||||||
|  | @ -334,12 +332,14 @@ local function parse_object(str, i) | ||||||
| 		i = next_char(str, i, space_chars, true) | 		i = next_char(str, i, space_chars, true) | ||||||
| 		local chr = str:sub(i, i) | 		local chr = str:sub(i, i) | ||||||
| 		i = i + 1 | 		i = i + 1 | ||||||
|     if chr == "}" then break end | 		if chr == "}" then  | ||||||
|     if chr ~= "," then decode_error(str, i, "expected '}' or ','") end | 			break;  | ||||||
| 		end | 		end | ||||||
|   return res, i | 		if chr ~= "," then  | ||||||
|  | 			decode_error(str, i, "expected '}' or ','") end | ||||||
| 		end | 		end | ||||||
| 
 | 	return res, i; | ||||||
|  | end; | ||||||
| 
 | 
 | ||||||
| local char_func_map = { | local char_func_map = { | ||||||
| 	[ '"' ] = parse_string, | 	[ '"' ] = parse_string, | ||||||
|  | @ -359,30 +359,27 @@ local char_func_map = { | ||||||
| 	[ "n" ] = parse_literal, | 	[ "n" ] = parse_literal, | ||||||
| 	[ "[" ] = parse_array, | 	[ "[" ] = parse_array, | ||||||
| 	[ "{" ] = parse_object, | 	[ "{" ] = parse_object, | ||||||
| } | }; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| parse = function(str, idx) | parse = function(str, idx) | ||||||
|   local chr = str:sub(idx, idx) | 	local chr = str:sub(idx, idx); | ||||||
|   local f = char_func_map[chr] | 	local f = char_func_map[chr]; | ||||||
| 	if f then | 	if f then | ||||||
|     return f(str, idx) | 		return f(str, idx); | ||||||
| 	end | 	end | ||||||
|   decode_error(str, idx, "unexpected character '" .. chr .. "'") | 	decode_error(str, idx, "unexpected character '" .. chr .. "'"); | ||||||
| end | end; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| function json.decode(str) | function json.decode(str) | ||||||
| 	if type(str) ~= "string" then | 	if type(str) ~= "string" then | ||||||
|     error("expected argument of type string, got " .. type(str)) | 		error("expected argument of type string, got " .. type(str)); | ||||||
| 	end | 	end | ||||||
| 	local res, idx = parse(str, next_char(str, 1, space_chars, true)) | 	local res, idx = parse(str, next_char(str, 1, space_chars, true)) | ||||||
| 	idx = next_char(str, idx, space_chars, true) | 	idx = next_char(str, idx, space_chars, true) | ||||||
| 	if idx <= #str then | 	if idx <= #str then | ||||||
| 		decode_error(str, idx, "trailing garbage") | 		decode_error(str, idx, "trailing garbage") | ||||||
| 	end | 	end | ||||||
|   return res | 	return res; | ||||||
| end | end; | ||||||
| 
 | 
 | ||||||
| 
 | return json; | ||||||
| return json |  | ||||||
		Loading…
	
		Reference in New Issue