clone url: git://git.m455.casa/fa
esperbuild/espersrc/fennel-0.7.0/fennelview.lua
1 | local function view_quote(str) |
2 | return ("\"" .. str:gsub("\"", "\\\"") .. "\"") |
3 | end |
4 | local short_control_char_escapes = {["\11"] = "\\v", ["\12"] = "\\f", ["\13"] = "\\r", ["\7"] = "\\a", ["\8"] = "\\b", ["\9"] = "\\t", ["\n"] = "\\n"} |
5 | local long_control_char_escapes = nil |
6 | do |
7 | local long = {} |
8 | for i = 0, 31 do |
9 | local ch = string.char(i) |
10 | if not short_control_char_escapes[ch] then |
11 | short_control_char_escapes[ch] = ("\\" .. i) |
12 | long[ch] = ("\\%03d"):format(i) |
13 | end |
14 | end |
15 | long_control_char_escapes = long |
16 | end |
17 | local function escape(str) |
18 | return str:gsub("\\", "\\\\"):gsub("(%c)%f[0-9]", long_control_char_escapes):gsub("%c", short_control_char_escapes) |
19 | end |
20 | local function sequence_key_3f(k, len) |
21 | return ((type(k) == "number") and (1 <= k) and (k <= len) and (math.floor(k) == k)) |
22 | end |
23 | local type_order = {["function"] = 5, boolean = 2, number = 1, string = 3, table = 4, thread = 7, userdata = 6} |
24 | local function sort_keys(a, b) |
25 | local ta = type(a) |
26 | local tb = type(b) |
27 | if ((ta == tb) and ((ta == "string") or (ta == "number"))) then |
28 | return (a < b) |
29 | else |
30 | local dta = type_order[a] |
31 | local dtb = type_order[b] |
32 | if (dta and dtb) then |
33 | return (dta < dtb) |
34 | elseif dta then |
35 | return true |
36 | elseif dtb then |
37 | return false |
38 | elseif "else" then |
39 | return (ta < tb) |
40 | end |
41 | end |
42 | end |
43 | local function get_sequence_length(t) |
44 | local len = 1 |
45 | for i in ipairs(t) do |
46 | len = i |
47 | end |
48 | return len |
49 | end |
50 | local function get_nonsequential_keys(t) |
51 | local keys = {} |
52 | local sequence_length = get_sequence_length(t) |
53 | for k in pairs(t) do |
54 | if not sequence_key_3f(k, sequence_length) then |
55 | table.insert(keys, k) |
56 | end |
57 | end |
58 | table.sort(keys, sort_keys) |
59 | return keys, sequence_length |
60 | end |
61 | local function count_table_appearances(t, appearances) |
62 | if (type(t) == "table") then |
63 | if not appearances[t] then |
64 | appearances[t] = 1 |
65 | for k, v in pairs(t) do |
66 | count_table_appearances(k, appearances) |
67 | count_table_appearances(v, appearances) |
68 | end |
69 | else |
70 | appearances[t] = ((appearances[t] or 0) + 1) |
71 | end |
72 | end |
73 | return appearances |
74 | end |
75 | local put_value = nil |
76 | local function puts(self, ...) |
77 | for _, v in ipairs({...}) do |
78 | table.insert(self.buffer, v) |
79 | end |
80 | return nil |
81 | end |
82 | local function tabify(self) |
83 | return puts(self, "\n", (self.indent):rep(self.level)) |
84 | end |
85 | local function already_visited_3f(self, v) |
86 | return (self.ids[v] ~= nil) |
87 | end |
88 | local function get_id(self, v) |
89 | local id = self.ids[v] |
90 | if not id then |
91 | local tv = type(v) |
92 | id = ((self["max-ids"][tv] or 0) + 1) |
93 | self["max-ids"][tv] = id |
94 | self.ids[v] = id |
95 | end |
96 | return tostring(id) |
97 | end |
98 | local function put_sequential_table(self, t, len) |
99 | puts(self, "[") |
100 | self.level = (self.level + 1) |
101 | for i = 1, len do |
102 | local _0_ = (1 + len) |
103 | if ((1 < i) and (i < _0_)) then |
104 | puts(self, " ") |
105 | end |
106 | put_value(self, t[i]) |
107 | end |
108 | self.level = (self.level - 1) |
109 | return puts(self, "]") |
110 | end |
111 | local function put_key(self, k) |
112 | if ((type(k) == "string") and k:find("^[-%w?\\^_!$%&*+./@:|<=>]+$")) then |
113 | return puts(self, ":", k) |
114 | else |
115 | return put_value(self, k) |
116 | end |
117 | end |
118 | local function put_kv_table(self, t, ordered_keys) |
119 | puts(self, "{") |
120 | self.level = (self.level + 1) |
121 | for i, k in ipairs(ordered_keys) do |
122 | if (self["table-edges"] or (i ~= 1)) then |
123 | tabify(self) |
124 | end |
125 | put_key(self, k) |
126 | puts(self, " ") |
127 | put_value(self, t[k]) |
128 | end |
129 | for i, v in ipairs(t) do |
130 | tabify(self) |
131 | put_key(self, i) |
132 | puts(self, " ") |
133 | put_value(self, v) |
134 | end |
135 | self.level = (self.level - 1) |
136 | if self["table-edges"] then |
137 | tabify(self) |
138 | end |
139 | return puts(self, "}") |
140 | end |
141 | local function put_table(self, t) |
142 | local metamethod = nil |
143 | local function _1_() |
144 | local _0_0 = t |
145 | if _0_0 then |
146 | local _2_0 = getmetatable(_0_0) |
147 | if _2_0 then |
148 | return _2_0.__fennelview |
149 | else |
150 | return _2_0 |
151 | end |
152 | else |
153 | return _0_0 |
154 | end |
155 | end |
156 | metamethod = (self["metamethod?"] and _1_()) |
157 | if (already_visited_3f(self, t) and self["detect-cycles?"]) then |
158 | return puts(self, "#<table @", get_id(self, t), ">") |
159 | elseif (self.level >= self.depth) then |
160 | return puts(self, "{...}") |
161 | elseif metamethod then |
162 | return puts(self, metamethod(t, self.fennelview)) |
163 | elseif "else" then |
164 | local non_seq_keys, len = get_nonsequential_keys(t) |
165 | local id = get_id(self, t) |
166 | if ((1 < (self.appearances[t] or 0)) and self["detect-cycles?"]) then |
167 | puts(self, "@", id) |
168 | end |
169 | if ((#non_seq_keys == 0) and (#t == 0)) then |
170 | local function _3_() |
171 | if self["empty-as-square"] then |
172 | return "[]" |
173 | else |
174 | return "{}" |
175 | end |
176 | end |
177 | return puts(self, _3_()) |
178 | elseif (#non_seq_keys == 0) then |
179 | return put_sequential_table(self, t, len) |
180 | elseif "else" then |
181 | return put_kv_table(self, t, non_seq_keys) |
182 | end |
183 | end |
184 | end |
185 | local function _0_(self, v) |
186 | local tv = type(v) |
187 | if (tv == "string") then |
188 | return puts(self, view_quote(escape(v))) |
189 | elseif ((tv == "number") or (tv == "boolean") or (tv == "nil")) then |
190 | return puts(self, tostring(v)) |
191 | elseif (tv == "table") then |
192 | return put_table(self, v) |
193 | elseif "else" then |
194 | return puts(self, "#<", tostring(v), ">") |
195 | end |
196 | end |
197 | put_value = _0_ |
198 | local function one_line(str) |
199 | local ret = str:gsub("\n", " "):gsub("%[ ", "["):gsub(" %]", "]"):gsub("%{ ", "{"):gsub(" %}", "}"):gsub("%( ", "("):gsub(" %)", ")") |
200 | return ret |
201 | end |
202 | local function fennelview(x, options) |
203 | local options0 = (options or {}) |
204 | local inspector = nil |
205 | local function _1_(_241) |
206 | return fennelview(_241, options0) |
207 | end |
208 | local function _2_() |
209 | if options0["one-line"] then |
210 | return "" |
211 | else |
212 | return " " |
213 | end |
214 | end |
215 | inspector = {["detect-cycles?"] = not (false == options0["detect-cycles?"]), ["empty-as-square"] = options0["empty-as-square"], ["max-ids"] = {}, ["metamethod?"] = not (false == options0["metamethod?"]), ["table-edges"] = (options0["table-edges"] ~= false), appearances = count_table_appearances(x, {}), buffer = {}, depth = (options0.depth or 128), fennelview = _1_, ids = {}, indent = (options0.indent or _2_()), level = 0} |
216 | put_value(inspector, x) |
217 | local str = table.concat(inspector.buffer) |
218 | if options0["one-line"] then |
219 | return one_line(str) |
220 | else |
221 | return str |
222 | end |
223 | end |
224 | return fennelview |