local function json_encode(obj)
	local function is_array(r)
		for k in pairs(r) do
			if type(k) ~= 'number' then
				return false
			end
		end
		return true
	end
	local function json_encode_value(x)
		if x == nil then return 'null'
		elseif type(x) == 'number' then
			return tostring(x)
		else return string.format('%q', tostring(x)) end
	end
	local function json_encode_table(tbl)
		local function json_encode_pair(k,v)
			return json_encode(k) .. ':' .. json_encode(v)
		end
		local json = {}
		for k,v in pairs(tbl) do
			json[#json + 1] = json_encode_pair(k,v)
		end
		return '{' .. table.concat(json, ',') .. '}'
	end
	local function json_encode_array(r)
		local json = {}
		for _,v in pairs(r) do
			json[#json + 1] = json_encode(v)
		end
		-- horrible hack needed to work around the difference in indexing
		return '[null, ' .. table.concat(json, ',') .. ']'
	end
	
	if type(obj) == 'table' then
		local head = next(obj)
		if head == nil then
			return '{}'
		elseif is_array(obj) then
			return json_encode_array(obj)
		else
			return json_encode_table(obj)
		end
	else
		return json_encode_value(obj)
	end
end

return { encode = json_encode }
