@tilua/compiler 6.1.0 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,255 @@
1
+ local __NAME__ = {}
2
+
3
+ -- JSON as tilua's values have it. A table is an array or an object by what
4
+ -- the program wrote — `[]` is an array and `{}` an object, empty or not —
5
+ -- which a Lua encoder, seeing only a table, cannot tell: `JSONEncode` writes
6
+ -- every empty table as `[]`. A table no tilua code made (a Lua library's) is
7
+ -- an array when its keys are 1 to its length, as before.
8
+ --
9
+ -- A table has no key whose value is nil, so two values stand in for what
10
+ -- JSON has and Luau does not: `null`, the key sent with no value, and
11
+ -- `undefined`, as JavaScript's — left out of an object, and `null` in an
12
+ -- array, where leaving it out would move what comes after it.
13
+
14
+ local NULL = setmetatable({}, { __tostring = function()
15
+ return "null"
16
+ end })
17
+ local UNDEFINED = setmetatable({}, { __tostring = function()
18
+ return "undefined"
19
+ end })
20
+
21
+ __NAME__.null = NULL
22
+ __NAME__.undefined = UNDEFINED
23
+
24
+ local function isList(t)
25
+ if __ARRAYS__[t] then
26
+ return true
27
+ end
28
+ if next(t) == nil then
29
+ return false
30
+ end
31
+ local count = 0
32
+ for _ in pairs(t) do
33
+ count = count + 1
34
+ end
35
+ return count == #t
36
+ end
37
+
38
+ local function escape(s)
39
+ return (s:gsub('[%c"\\]', function(c)
40
+ if c == '"' then
41
+ return '\\"'
42
+ elseif c == "\\" then
43
+ return "\\\\"
44
+ elseif c == "\n" then
45
+ return "\\n"
46
+ elseif c == "\r" then
47
+ return "\\r"
48
+ elseif c == "\t" then
49
+ return "\\t"
50
+ end
51
+ return string.format("\\u%04x", string.byte(c))
52
+ end))
53
+ end
54
+
55
+ local encode
56
+
57
+ local function encodeTable(t, seen)
58
+ if seen[t] then
59
+ error("JSON cannot hold a table that holds itself", 0)
60
+ end
61
+ seen[t] = true
62
+ local parts = {}
63
+ if isList(t) then
64
+ for i = 1, #t do
65
+ local item = t[i]
66
+ parts[i] = item == UNDEFINED and "null" or encode(item, seen)
67
+ end
68
+ seen[t] = nil
69
+ return "[" .. table.concat(parts, ",") .. "]"
70
+ end
71
+ -- Written in order, so one value is always one string.
72
+ local keys = {}
73
+ for key, item in pairs(t) do
74
+ local kind = type(key)
75
+ if kind ~= "string" and kind ~= "number" then
76
+ error("JSON keys are strings: cannot write a " .. kind .. " key", 0)
77
+ end
78
+ if item ~= UNDEFINED then
79
+ keys[#keys + 1] = key
80
+ end
81
+ end
82
+ table.sort(keys, function(a, b)
83
+ return tostring(a) < tostring(b)
84
+ end)
85
+ for i, key in ipairs(keys) do
86
+ parts[i] = '"' .. escape(tostring(key)) .. '":' .. encode(t[key], seen)
87
+ end
88
+ seen[t] = nil
89
+ return "{" .. table.concat(parts, ",") .. "}"
90
+ end
91
+
92
+ encode = function(value, seen)
93
+ if value == nil or value == NULL or value == UNDEFINED then
94
+ return "null"
95
+ end
96
+ local kind = type(value)
97
+ if kind == "string" then
98
+ return '"' .. escape(value) .. '"'
99
+ elseif kind == "number" then
100
+ if value ~= value or value == math.huge or value == -math.huge then
101
+ return "null"
102
+ end
103
+ return tostring(value)
104
+ elseif kind == "boolean" then
105
+ return tostring(value)
106
+ elseif kind == "table" then
107
+ return encodeTable(value, seen)
108
+ end
109
+ error("JSON cannot hold a " .. (typeof or type)(value), 0)
110
+ end
111
+
112
+ function __NAME__.encode(value)
113
+ return encode(value, {})
114
+ end
115
+
116
+ -- ============================================================
117
+ -- Reading it back
118
+ -- ============================================================
119
+ --
120
+ -- An array comes back an array (`typeof` says so) and an object an object,
121
+ -- empty or not. `null` is nil: a key that holds it is not there.
122
+
123
+ local ESCAPES = { ['"'] = '"', ["\\"] = "\\", ["/"] = "/", b = "\b", f = "\f", n = "\n", r = "\r", t = "\t" }
124
+
125
+ local function fail(text, at, what)
126
+ local line = 1
127
+ for _ in text:sub(1, at - 1):gmatch("\n") do
128
+ line = line + 1
129
+ end
130
+ error("Invalid JSON at line " .. line .. ": " .. what, 0)
131
+ end
132
+
133
+ local function skip(text, at)
134
+ return text:find("[^ \t\r\n]", at) or #text + 1
135
+ end
136
+
137
+ local decodeValue
138
+
139
+ local function decodeString(text, at)
140
+ local parts = {}
141
+ local i = at + 1
142
+ while true do
143
+ local stop = text:find('["\\]', i)
144
+ if stop == nil then
145
+ fail(text, at, "a string that never ends")
146
+ end
147
+ parts[#parts + 1] = text:sub(i, stop - 1)
148
+ if text:sub(stop, stop) == '"' then
149
+ return table.concat(parts), stop + 1
150
+ end
151
+ local c = text:sub(stop + 1, stop + 1)
152
+ if c == "u" then
153
+ local hex = text:sub(stop + 2, stop + 5)
154
+ local code = tonumber(hex, 16)
155
+ if code == nil or #hex < 4 then
156
+ fail(text, stop, "a \\u escape without four hex digits")
157
+ end
158
+ i = stop + 6
159
+ -- A surrogate pair is one character.
160
+ if code >= 0xD800 and code <= 0xDBFF and text:sub(i, i + 1) == "\\u" then
161
+ local low = tonumber(text:sub(i + 2, i + 5), 16)
162
+ if low ~= nil and low >= 0xDC00 and low <= 0xDFFF then
163
+ code = 0x10000 + (code - 0xD800) * 0x400 + (low - 0xDC00)
164
+ i = i + 6
165
+ end
166
+ end
167
+ parts[#parts + 1] = utf8 ~= nil and utf8.char(code) or "?"
168
+ else
169
+ local escaped = ESCAPES[c]
170
+ if escaped == nil then
171
+ fail(text, stop, "an unknown escape '\\" .. c .. "'")
172
+ end
173
+ parts[#parts + 1] = escaped
174
+ i = stop + 2
175
+ end
176
+ end
177
+ end
178
+
179
+ decodeValue = function(text, at)
180
+ at = skip(text, at)
181
+ local c = text:sub(at, at)
182
+ if c == "{" then
183
+ local out = {}
184
+ at = skip(text, at + 1)
185
+ if text:sub(at, at) == "}" then
186
+ return out, at + 1
187
+ end
188
+ while true do
189
+ at = skip(text, at)
190
+ if text:sub(at, at) ~= '"' then
191
+ fail(text, at, "an object key that is not a string")
192
+ end
193
+ local key
194
+ key, at = decodeString(text, at)
195
+ at = skip(text, at)
196
+ if text:sub(at, at) ~= ":" then
197
+ fail(text, at, "a key without ':'")
198
+ end
199
+ local value
200
+ value, at = decodeValue(text, at + 1)
201
+ out[key] = value
202
+ at = skip(text, at)
203
+ local next = text:sub(at, at)
204
+ if next == "}" then
205
+ return out, at + 1
206
+ elseif next ~= "," then
207
+ fail(text, at, "an object without ',' or '}'")
208
+ end
209
+ at = at + 1
210
+ end
211
+ elseif c == "[" then
212
+ local out = __ARRAY__({})
213
+ local n = 0
214
+ at = skip(text, at + 1)
215
+ if text:sub(at, at) == "]" then
216
+ return out, at + 1
217
+ end
218
+ while true do
219
+ local value
220
+ value, at = decodeValue(text, at)
221
+ n = n + 1
222
+ out[n] = value
223
+ at = skip(text, at)
224
+ local next = text:sub(at, at)
225
+ if next == "]" then
226
+ return out, at + 1
227
+ elseif next ~= "," then
228
+ fail(text, at, "an array without ',' or ']'")
229
+ end
230
+ at = at + 1
231
+ end
232
+ elseif c == '"' then
233
+ return decodeString(text, at)
234
+ elseif text:sub(at, at + 3) == "true" then
235
+ return true, at + 4
236
+ elseif text:sub(at, at + 4) == "false" then
237
+ return false, at + 5
238
+ elseif text:sub(at, at + 3) == "null" then
239
+ return nil, at + 4
240
+ end
241
+ local number = text:match("^-?%d+%.?%d*[eE]?[-+]?%d*", at)
242
+ if number == nil or number == "" or tonumber(number) == nil then
243
+ fail(text, at, c == "" and "nothing where a value belongs" or ("an unexpected '" .. c .. "'"))
244
+ end
245
+ return tonumber(number), at + #number
246
+ end
247
+
248
+ function __NAME__.decode(text)
249
+ local value, at = decodeValue(text, 1)
250
+ at = skip(text, at)
251
+ if at <= #text then
252
+ fail(text, at, "more after the value")
253
+ end
254
+ return value
255
+ end