summaryrefslogtreecommitdiff
path: root/script-beta/src/json/encode.lua
blob: 492c5a585d6311059d54658f577babf2540c62c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
local rep          = string.rep
local gsub         = string.gsub
local sort         = table.sort
local find         = string.find
local tostring     = tostring
local getmetatable = debug.getmetatable
local type         = type
local next         = next
local pairs        = pairs
local tableConcat  = table.concat

_ENV = nil

local index
local lines
local n = -1
local tabs = {}

local esc_map = {
	['\\'] = '\\\\',
	['\r'] = '\\r',
	['\n'] = '\\n',
	['\t'] = '\\t',
	['"']  = '\\"',
}

local function encode(data, key)
	n = n + 1
	if not tabs[n] then
		tabs[n] = rep('    ', n)
	end
	local tp = type(data)
	if tp == 'table' then
		if not data[1] and next(data) then
			-- 认为这个是哈希表
			if key then
				index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": {\r\n'
			else
				index=index+1;lines[index] = tabs[n] .. '{\r\n'
			end
			local meta = getmetatable(data)
			local sep
			if meta and meta.__pairs then
				for k, v in meta.__pairs(data), data do
					if encode(v, k) then
						index=index+1;lines[index] = ',\r\n'
						sep = true
					end
				end
			else
				local list = {}
				local i = 0
				for k in next, data do
					i=i+1;list[i] = k
				end
				sort(list)
				for j = 1, i do
					local k = list[j]
					if encode(data[k], k) then
						index=index+1;lines[index] = ',\r\n'
						sep = true
					end
				end
			end
			if sep then
				lines[index] = '\r\n'
			end
			index=index+1;lines[index] = tabs[n] .. '}'
		else
			-- 认为这个是数组
			if key then
				index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": [\r\n'
			else
				index=index+1;lines[index] = tabs[n] .. '[\r\n'
			end
			local sep
			for k, v in pairs(data) do
				if encode(v) then
					index=index+1;lines[index] = ',\r\n'
					sep = true
				end
			end
			if sep then
				lines[index] = '\r\n'
			end
			index=index+1;lines[index] = tabs[n] .. ']'
		end
	elseif tp == 'number' then
		data = tostring(data)
		-- 判断 inf -inf -nan(ind) 1.#INF -1.#INF -1.#IND
		if find(data, '%a') then
			data = '0'
		end
		if key then
			index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": ' .. data
		else
			index=index+1;lines[index] = tabs[n] .. data
		end
	elseif tp == 'boolean' then
		if key then
			index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": ' .. tostring(data)
		else
			index=index+1;lines[index] = tabs[n] .. tostring(data)
		end
	elseif tp == 'nil' then
		if key then
			index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": null'
		else
			index=index+1;lines[index] = tabs[n] .. 'null'
		end
	elseif tp == 'string' then
		local str = gsub(data, '[\\\r\n\t"]', esc_map)
		if key then
			index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": "' .. str .. '"'
		else
			index=index+1;lines[index] = tabs[n] .. '"' .. str .. '"'
		end
	else
		n = n - 1
		return false
	end
	n = n - 1
	return true
end

local function json(t)
	lines = {}
	index = 0

	encode(t)

	return tableConcat(lines)
end

return json