-
Notifications
You must be signed in to change notification settings - Fork 3
/
ugly.lua
204 lines (185 loc) · 5.94 KB
/
ugly.lua
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
-- Reimplementation of some pl.pretty functions with a stack depth limit (default 1).
-- NOTE: THIS FILE SUBSTANTIALLY REUSES PENLIGHT CODE AND IS UNDER THE PENLIGHT LICENSE, NOT THE LOVR-ENT LICENSE
namespace "minimal"
local ugly = {}
local append = table.insert
local concat = table.concat
local mfloor, mhuge = math.floor, math.huge
local mtype = math.type
local lexer = require 'pl.lexer'
local quote_string = require'pl.stringx'.quote_string
local original_tostring = tostring
local keywords
-- Patch tostring to format numbers with better precision
-- and to produce cross-platform results for
-- infinite values and NaN.
local function tostring(value)
if type(value) ~= "number" then
return original_tostring(value)
elseif value ~= value then
return "NaN"
elseif value == mhuge then
return "Inf"
elseif value == -mhuge then
return "-Inf"
elseif (_VERSION ~= "Lua 5.3" or mtype(value) == "integer") and mfloor(value) == value then
return ("%d"):format(value)
else
local res = ("%.14g"):format(value)
if _VERSION == "Lua 5.3" and mtype(value) == "float" and not res:find("%.") then
-- Number is internally a float but looks like an integer.
-- Insert ".0" after first run of digits.
res = res:gsub("%d+", "%0.0", 1)
end
return res
end
end
local function quote_if_necessary (v)
if not v then return ''
else
--AAS
if v:find ' ' then v = quote_string(v) end
end
return v
end
local function is_identifier (s)
return type(s) == 'string' and s:find('^[%a_][%w_]*$') and not keywords[s]
end
local function quote (s)
if type(s) == 'table' then
return pretty.write(s,'')
else
--AAS
return quote_string(s)-- ('%q'):format(tostring(s))
end
end
local function index (numkey,key)
--AAS
if not numkey then
key = quote(key)
key = key:find("^%[") and (" " .. key .. " ") or key
end
return '['..key..']'
end
--- Create a string representation of a Lua table.
-- This function never fails, but may complain by returning an
-- extra value. Normally puts out one item per line, using
-- the provided indent; set the second parameter to an empty string
-- if you want output on one line.
-- @tab tbl Table to serialize to a string.
-- @string[opt] space The indent to use.
-- Defaults to two spaces; pass an empty string for no indentation.
-- @bool[opt] not_clever Pass `true` for plain output, e.g `{['key']=1}`.
-- Defaults to `false`.
-- @return a string
-- @return an optional error message
function ugly.write (tbl,space,not_clever,limit)
if type(tbl) ~= 'table' then
local res = tostring(tbl)
if type(tbl) == 'string' then return quote(tbl) end
return res, 'not a table'
end
if not limit then limit = 1 end
if not keywords then
keywords = lexer.get_keywords()
end
local set = ' = '
if space == '' then set = '=' end
space = space or ' '
local lines = {}
local line = ''
local tables = {}
local function put(s)
if #s > 0 then
line = line..s
end
end
local function putln (s)
if #line > 0 then
line = line..s
append(lines,line)
line = ''
else
append(lines,s)
end
end
local function eat_last_comma ()
local n = #lines
local lastch = lines[n]:sub(-1,-1)
if lastch == ',' then
lines[n] = lines[n]:sub(1,-2)
end
end
local writeit
writeit = function (t,oldindent,indent,limit)
local tp = type(t)
if tp ~= 'string' and tp ~= 'table' then
putln(quote_if_necessary(tostring(t))..',')
elseif tp == 'string' then
-- if t:find('\n') then
-- putln('[[\n'..t..']],')
-- else
-- putln(quote(t)..',')
-- end
--AAS
putln(quote_string(t) ..",")
elseif tp == 'table' and limit > 0 then
if tables[t] then
putln('<cycle>,')
return
end
tables[t] = true
local newindent = indent..space
putln('{')
local used = {}
if not not_clever then
for i,val in ipairs(t) do
put(indent)
writeit(val,indent,newindent,limit-1)
used[i] = true
end
end
for key,val in pairs(t) do
local tkey = type(key)
local numkey = tkey == 'number'
if not_clever then
key = tostring(key)
put(indent..index(numkey,key)..set)
writeit(val,indent,newindent,limit-1)
else
if not numkey or not used[key] then -- non-array indices
if tkey ~= 'string' then
key = tostring(key)
end
if numkey or not is_identifier(key) then
key = index(numkey,key)
end
put(indent..key..set)
writeit(val,indent,newindent,limit-1)
end
end
end
tables[t] = nil
eat_last_comma()
putln(oldindent..'},')
else
putln(tostring(t)..',')
end
end
writeit(tbl,'',space,limit)
eat_last_comma()
return concat(lines,#space > 0 and '\n' or '')
end
--- Dump a Lua table out to a file or stdout.
-- @tab t The table to write to a file or stdout.
-- @string[opt] filename File name to write too. Defaults to writing
-- to stdout.
function ugly.dump (t, filename, limit)
if not filename then
print(ugly.write(t, limit))
return true
else
return utils.writefile(filename, ugly.write(t, limit))
end
end
return ugly