aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2025-11-04 17:00:46 +0800
committerLi Jin <dragon-fly@qq.com>2025-11-04 17:00:46 +0800
commitccd9c7f216c341b50e0a0313ac2eef6a89cee5a4 (patch)
tree153ce8766144c7f4288772a1fe668590f60e42a5 /src
parent03d4fad6ef79ce1788391648e535039a5f29aec3 (diff)
downloadyuescript-ccd9c7f216c341b50e0a0313ac2eef6a89cee5a4.tar.gz
yuescript-ccd9c7f216c341b50e0a0313ac2eef6a89cee5a4.tar.bz2
yuescript-ccd9c7f216c341b50e0a0313ac2eef6a89cee5a4.zip
Included a minimal json lib in yue compiler tool.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/3rdParty/colib/LICENSE21
-rwxr-xr-xsrc/3rdParty/colib/ljson.c900
-rw-r--r--src/yue.cpp10
3 files changed, 930 insertions, 1 deletions
diff --git a/src/3rdParty/colib/LICENSE b/src/3rdParty/colib/LICENSE
new file mode 100755
index 0000000..e0eddeb
--- /dev/null
+++ b/src/3rdParty/colib/LICENSE
@@ -0,0 +1,21 @@
1MIT License
2
3Copyright (c) 2020 colin
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
diff --git a/src/3rdParty/colib/ljson.c b/src/3rdParty/colib/ljson.c
new file mode 100755
index 0000000..78f9070
--- /dev/null
+++ b/src/3rdParty/colib/ljson.c
@@ -0,0 +1,900 @@
1/**
2 * json解析器:只支持utf-8格式,Lua只支持64位的数字
3 */
4#define LUA_LIB
5#include <stdlib.h>
6#include <string.h>
7#include <stdint.h>
8#include <stdio.h>
9#include <ctype.h>
10#include <assert.h>
11#include <errno.h>
12#include <setjmp.h>
13#include <ctype.h>
14#include <limits.h>
15#include <float.h>
16#include <math.h>
17#include "lua.h"
18#include "lauxlib.h"
19
20// 内存分配函数,方便替换
21#define co_malloc malloc
22#define co_free free
23#define co_realloc realloc
24#define co_calloc calloc
25
26
27#if !defined(likely)
28#if defined(__GNUC__)
29#define likely(x) (__builtin_expect(((x) != 0), 1))
30#define unlikely(x) (__builtin_expect(((x) != 0), 0))
31#else
32#define likely(x) (x)
33#define unlikely(x) (x)
34#endif
35
36#endif
37
38//-----------------------------------------------------------------------------
39// membuffer
40
41#define STACK_BUFF_SIZE 512
42
43typedef struct membuffer {
44 char *b; // 内存buffer
45 size_t sz; // buffer已用长度
46 size_t cap; // buffer实际大小
47 char s[STACK_BUFF_SIZE];
48} membuffer_t;
49
50// 初始化buffer
51static inline void membuffer_init(membuffer_t *buff) {
52 buff->b = buff->s;
53 buff->cap = STACK_BUFF_SIZE;
54 buff->sz = 0;
55}
56
57static inline void membuffer_add_size(membuffer_t *buff, size_t sz) {
58 buff->sz += sz;
59}
60
61static inline void membuffer_reset(membuffer_t *buff) {
62 buff->sz = 0;
63}
64
65static inline void membuffer_free(membuffer_t *buff) {
66 if (buff->b && buff->b != buff->s) {
67 co_free(buff->b);
68 buff->b = NULL;
69 }
70}
71
72static inline void _membuffer_grow(membuffer_t *buff, size_t needsz) {
73 if (buff->cap < needsz) {
74 size_t newcap = buff->cap * 2;
75 if (newcap < needsz)
76 newcap = needsz;
77 if (buff->b == buff->s) {
78 buff->b = (char*)co_malloc(newcap);
79 memcpy(buff->b, buff->s, buff->sz);
80 } else {
81 buff->b = (char*)co_realloc(buff->b, newcap);
82 }
83 buff->cap = newcap;
84 }
85}
86
87// 确保缓存中还有sz的可用空间
88static inline void membuffer_ensure_space(membuffer_t *buff, size_t sz) {
89 if (buff->sz + sz > buff->cap) {
90 _membuffer_grow(buff, buff->sz+sz);
91 }
92}
93
94// 压入一个字符
95static inline void membuffer_putc(membuffer_t *buff, char c) {
96 membuffer_ensure_space(buff, 1);
97 buff->b[buff->sz++] = c;
98}
99
100// 写入一段内存
101static inline void membuffer_putb(membuffer_t *buff, const void *b, size_t sz) {
102 membuffer_ensure_space(buff, sz);
103 memcpy(buff->b + buff->sz, b, sz);
104 buff->sz += sz;
105}
106
107// 压入一个字符:不检查空间(不安全版本)
108static inline void membuffer_putc_unsafe(membuffer_t *buff, char c) {
109 buff->b[buff->sz++] = c;
110}
111
112// 写入一段内存:不检查空间(不安全版本)
113static inline void membuffer_putb_unsafe(membuffer_t *buff, const void *b, size_t sz) {
114 memcpy(buff->b + buff->sz, b, sz);
115 buff->sz += sz;
116}
117
118// 取当前的指针
119static inline char* membuffer_getp(membuffer_t *buff) {
120 return buff->b + buff->sz;
121}
122
123//-----------------------------------------------------------------------------
124// parser
125
126//-------------------------------------
127// 与Lua相关的代码
128
129static inline void l_add_object(lua_State *L) {
130 luaL_checkstack(L, 6, NULL);
131 lua_createtable(L, 0, 4);
132}
133static inline void l_begin_pair(lua_State *L, const char *k, size_t sz) {
134 lua_pushlstring(L, k, sz);
135}
136static inline void l_end_pair(lua_State *L) {
137 lua_rawset(L, -3);
138}
139static inline void l_add_array(lua_State *L) {
140 luaL_checkstack(L, 6, NULL);
141 lua_createtable(L, 4, 0);
142}
143static inline void l_add_index(lua_State *L, int i) {
144 lua_rawseti(L, -2, i+1);
145}
146static inline void l_add_string(lua_State *L, const char *s, size_t sz) {
147 lua_pushlstring(L, s, sz);
148}
149static inline void l_add_float(lua_State *L, double f) {
150 lua_pushnumber(L, (lua_Number)f);
151}
152static inline void l_add_integer(lua_State *L, int64_t i) {
153 lua_pushinteger(L, (lua_Integer)i);
154}
155static inline void l_add_boolean(lua_State *L, int b) {
156 lua_pushboolean(L, b);
157}
158static inline void l_add_null(lua_State *L) {
159 lua_pushlightuserdata(L, NULL);
160}
161static inline void l_error(lua_State *L, const char *msg) {
162 luaL_error(L, msg);
163}
164
165// 解析事件
166#define ON_ADD_OBJECT(ud) l_add_object((lua_State*)(ud))
167#define ON_BEGIN_PAIR(ud, k, sz) l_begin_pair((lua_State*)(ud), k, sz)
168#define ON_END_PAIR(ud) l_end_pair((lua_State*)(ud))
169#define ON_ADD_ARRAY(ud) l_add_array((lua_State*)(ud))
170#define ON_ADD_INDEX(ud, i) l_add_index((lua_State*)(ud), i)
171#define ON_ADD_STRING(ud, s, sz) l_add_string((lua_State*)(ud), s, sz)
172#define ON_ADD_FLOAT(ud, f) l_add_float((lua_State*)(ud), f)
173#define ON_ADD_INTEGER(ud, i) l_add_integer((lua_State*)(ud), i)
174#define ON_ADD_BOOLEAN(ud, b) l_add_boolean((lua_State*)(ud), b)
175#define ON_ADD_NULL(ud) l_add_null((lua_State*)(ud))
176#define ON_ERROR(ud, msg) l_error((lua_State*)(ud), msg)
177
178//-------------------------------------
179// 解析json,这部分代码与Lua无关,是通用的解析器;如果要移植这部分代码,需要把 //>>> 开头的注释去掉
180
181// 错误消息的大小
182#define ERRMSG_SIZE 256
183
184// json解析器
185typedef struct {
186 const char *str; // json字符串
187 const char *ptr; // json字符串解析指针
188 void *ud; // 解析事件的用户数据
189 membuffer_t buff; // 临时缓存
190 int curdepth; // 当前层次
191 int maxdepth; // 最大层次
192 int allowcomment; // 是否允许注释
193 char errmsg[ERRMSG_SIZE]; // 保存错误消息
194 //>>>jmp_buf jb; // 用于实现从解析中出错直接跳出
195} json_parser_t;
196
197static inline void parser_init(json_parser_t *parser, const char *str, size_t size, void *ud,
198 int maxdepth, int allowcomment) {
199 membuffer_init(&parser->buff);
200 membuffer_ensure_space(&parser->buff, size);
201 parser->str = str;
202 parser->ptr = str;
203 parser->ud = ud;
204 parser->maxdepth = maxdepth;
205 parser->curdepth = 0;
206 parser->allowcomment = allowcomment;
207}
208
209static inline void parser_free(json_parser_t *parser) {
210 membuffer_free(&parser->buff);
211}
212
213// 抛出错误
214static void parser_throw_error(json_parser_t *parser, const char *fmt, ...) {
215 membuffer_free(&parser->buff);
216 va_list arg;
217 va_start(arg, fmt);
218 vsnprintf(parser->errmsg, ERRMSG_SIZE, fmt, arg);
219 va_end(arg);
220 ON_ERROR(parser->ud, parser->errmsg);
221 // 直接跳出解析代码,由于Lua的lua_error也是用longjmp,所以下面的代码没有机会执行到。但其他语言就不一定。
222 //>>>longjmp(parser->jb, 1);
223}
224
225// 辅助宏
226#define peekchar(p) (*(p)->ptr)
227#define skipchar(p) (++(p)->ptr)
228#define get_and_next(p) (*(p)->ptr++)
229#define next_and_get(p) (*(++(p)->ptr))
230#define savechar(p, c) membuffer_putc_unsafe(&(p)->buff, (c))
231#define currpos(p) (size_t)((p)->ptr - (p)->str)
232
233// 取解析到的错误内容
234static const char* parser_error_content(json_parser_t *p) {
235 size_t n = currpos(p);
236 if (n > 50) n = 50; // 调整这个数获得更长的内容
237 membuffer_reset(&p->buff);
238 membuffer_putb(&p->buff, p->ptr - n, n);
239 membuffer_putc(&p->buff, '\0');
240 return p->buff.b;
241}
242
243// 增加深度
244static inline void parser_add_depth(json_parser_t *p) {
245 p->curdepth++;
246 if (p->curdepth >= p->maxdepth)
247 parser_throw_error(p, "Too many nested data, max depth is %d, at: %s[:%lu]", p->maxdepth,
248 parser_error_content(p), currpos(p));
249}
250
251static inline void parser_skip_whitespaces(json_parser_t *p) {
252 // colin: 要支持注释,请将下面注释去掉
253 // if (likely(!p->allowcomment)) {
254 char ch = peekchar(p);
255 while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
256 ch = next_and_get(p);
257 // } else {
258 // char ch = peekchar(p);
259 // for (;;) {
260 // while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
261 // ch = next_and_get(p);
262 // if (ch == '/') {
263 // ch = next_and_get(p);
264 // if (ch == '/') {
265 // ch = next_and_get(p);
266 // while (ch != '\n' && ch != '\r' && ch != '\0')
267 // ch = next_and_get(p);
268 // continue;
269 // } else {
270 // parser_throw_error(p, "Invalid comment, at: %s[:%lu]", parser_error_content(p), currpos(p));
271 // }
272 // }
273 // break;
274 // }
275 // }
276}
277
278static inline void parser_expect_char(json_parser_t *p, char c) {
279 if (likely(peekchar(p) == c))
280 skipchar(p);
281 else
282 parser_throw_error(p, "Expect '%c' at: %s[:%lu]", c, parser_error_content(p), currpos(p));
283}
284
285static inline void parser_process_false(json_parser_t *p) {
286 if (likely(p->ptr[0] == 'a' && p->ptr[1] == 'l' && p->ptr[2] == 's' && p->ptr[3] == 'e')) {
287 p->ptr += 4;
288 ON_ADD_BOOLEAN(p->ud, 0);
289 } else {
290 parser_throw_error(p, "Invalid boolean, at: %s[:%lu]", parser_error_content(p), currpos(p));
291 }
292}
293
294static inline void parser_process_true(json_parser_t *p) {
295 if (likely(p->ptr[0] == 'r' && p->ptr[1] == 'u' && p->ptr[2] == 'e')) {
296 p->ptr += 3;
297 ON_ADD_BOOLEAN(p->ud, 1);
298 } else {
299 parser_throw_error(p, "Invalid boolean, at: %s[:%lu]", parser_error_content(p), currpos(p));
300 }
301}
302
303static inline void parser_process_null(json_parser_t *p) {
304 if (likely(p->ptr[0] == 'u' && p->ptr[1] == 'l' && p->ptr[2] == 'l')) {
305 p->ptr += 3;
306 ON_ADD_NULL(p->ud);
307 } else {
308 parser_throw_error(p, "Invalid null, at: %s[:%lu]", parser_error_content(p), currpos(p));
309 }
310}
311
312static inline uint32_t parser_read_hex(json_parser_t *p) {
313 uint32_t cp = 0;
314 unsigned char ch;
315 int i = 4;
316 while (i--) {
317 ch = (unsigned char)get_and_next(p);
318 if ('0' <= ch && ch <= '9')
319 ch -= '0';
320 else if (ch >= 'a' && ch <= 'f')
321 ch = ch - 'a' + 10;
322 else if (ch >= 'A' && ch <= 'F')
323 ch = ch - 'A' + 10;
324 else {
325 parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
326 return cp;
327 }
328 cp = (cp << 4) + ch;
329 }
330 return cp;
331}
332
333static inline void parser_process_utf8esc(json_parser_t *p) {
334 uint32_t cp = parser_read_hex(p);
335 // UTF-16 surrogate pairs, see https://unicodebook.readthedocs.io/unicode_encodings.html#utf-16-surrogate-pairs
336 if (cp >= 0xD800 && cp <= 0xDBFF) {
337 char p0 = p->ptr[0];
338 char p1 = p->ptr[1];
339 if (p0 != '\\' || p1 != 'u')
340 parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
341 p->ptr += 2;
342 uint32_t cp2 = parser_read_hex(p);
343 if (cp2 < 0xDC00 || cp2 > 0xDFFF)
344 parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
345 cp = 0x10000 + (((cp & 0x03FF) << 10) | (cp2 & 0x03FF));
346 }
347 if (cp < 0x80) {
348 membuffer_putc_unsafe(&p->buff, (char)cp);
349 } else if (cp < 0x800) {
350 membuffer_putc_unsafe(&p->buff, 0xC0 | (cp >> 6));
351 membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F));
352 } else if (cp < 0x10000) {
353 membuffer_putc_unsafe(&p->buff, 0xE0 | (cp >> 12));
354 membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 6) & 0x3F));
355 membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F));
356 } else {
357 membuffer_putc_unsafe(&p->buff, 0xF0 | (cp >> 18));
358 membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 12) & 0x3F));
359 membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 6) & 0x3F));
360 membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F));
361 }
362}
363
364static const char escape2char[256] = {
365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0~19
366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\"',0, 0, 0, 0, 0, // 20~39
367 0, 0, 0, 0, 0, 0, 0, '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40~59
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60~79
369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\',0, 0, 0, 0, 0, '\b',0, // 80~99
370 0, 0, '\f',0, 0, 0, 0, 0, 0, 0, '\n',0, 0, 0, '\r',0, '\t',0, 0, 0, // 100~119
371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120~139
372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140~159
373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160~179
374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180~199
375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200~219
376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220~239
377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240~256
378};
379
380static inline void parser_process_string(json_parser_t *p) {
381 membuffer_reset(&p->buff);
382 char ch = get_and_next(p);
383 for (;;) {
384 if (ch == '\\') {
385 unsigned char nch = (unsigned char)peekchar(p);
386 if (likely(escape2char[nch])) {
387 savechar(p, escape2char[nch]);
388 skipchar(p);
389 } else if (nch == 'u') {
390 skipchar(p);
391 parser_process_utf8esc(p);
392 } else {
393 parser_throw_error(p, "Invalid escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
394 }
395 } else if (ch == '"') {
396 break;
397 } else if ((unsigned char)ch < 0x20) {
398 parser_throw_error(p, "Invalid string, at: %s[:%lu]", parser_error_content(p), currpos(p));
399 } else {
400 savechar(p, ch);
401 }
402 ch = get_and_next(p);
403 }
404}
405
406#define invalid_number(p) parser_throw_error(p, "Invalid value, at: %s[:%lu]", parser_error_content(p), currpos(p))
407#define MAXBY10 (int64_t)(922337203685477580)
408#define MAXLASTD (int)(7)
409static double powersOf10[] = {10., 100., 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256};
410static inline void parser_process_number(json_parser_t *p, char ch) {
411 double db; // 浮点数
412 int64_t in = 0; // 整型值
413 int isdouble = 0; // 是否是浮点数
414 int neg = 0; // 是否是负数
415 int exponent = 0; // 指数位数
416
417 if (ch == '-') { // 负值
418 neg = 1;
419 ch = get_and_next(p);
420 }
421 if (unlikely(ch == '0')) { // 0开头的后面只能是:.eE或\0
422 ch = peekchar(p);
423 } else if (likely(ch >= '1' && ch <= '9')) {
424 in = ch - '0';
425 ch = peekchar(p);
426 while (ch >= '0' && ch <= '9') {
427 if (unlikely(in >= MAXBY10 && (in > MAXBY10 || (ch - '0') > MAXLASTD + neg))) { // 更大的数字就用浮点数表示
428 isdouble = 1;
429 db = (double)in;
430 do {
431 db = db * 10.0 + (ch - '0');
432 ch = next_and_get(p);
433 } while (ch >= '0' && ch <= '9');
434 break;
435 }
436 in = in * 10 + (ch - '0');
437 ch = next_and_get(p);
438 }
439 } else {
440 invalid_number(p);
441 }
442
443 if (ch == '.') { // 小数点部分
444 if (likely(!isdouble)) {
445 isdouble = 1;
446 db = (double)in;
447 }
448 ch = next_and_get(p);
449 if (unlikely(!(ch >= '0' && ch <= '9')))
450 invalid_number(p); // .后面一定是数字
451 do {
452 db = db * 10. + (ch - '0');
453 exponent--;
454 ch = next_and_get(p);
455 } while (ch >= '0' && ch <= '9');
456 }
457
458 if (ch == 'e' || ch == 'E') { // 指数部分
459 if (!isdouble) { // 有e强制认为是浮点数
460 isdouble = 1;
461 db = (double)in;
462 }
463 ch = next_and_get(p);
464 int eneg = 0;
465 if (ch == '-') {
466 eneg = 1;
467 ch = next_and_get(p);
468 } else if (ch == '+') {
469 ch = next_and_get(p);
470 }
471 if (unlikely(!(ch >= '0' && ch <= '9')))
472 invalid_number(p); // 后面一定是数字
473 int exp = 0;
474 do {
475 exp = exp * 10. + (ch - '0');
476 ch = next_and_get(p);
477 } while (ch >= '0' && ch <= '9');
478 exponent += eneg ? (-exp) : (exp);
479 }
480
481 if (isdouble) {
482 int n = exponent < 0 ? -exponent : exponent;
483 if (unlikely(n>511))
484 n = 511; // inf
485 double p10 = 1.0;
486 double *d;
487 for (d = powersOf10; n != 0; n >>= 1, d += 1) {
488 if (n & 1) p10 *= *d;
489 }
490 if (exponent < 0)
491 db /= p10;
492 else
493 db *= p10;
494 if (neg) db = -db;
495 ON_ADD_FLOAT(p->ud, db);
496 } else {
497 if (neg) in = -in;
498 ON_ADD_INTEGER(p->ud, in);
499 }
500}
501
502static void parser_process_value(json_parser_t *p);
503
504static inline void parser_process_object(json_parser_t *p) {
505 parser_add_depth(p);
506 ON_ADD_OBJECT(p->ud);
507 parser_skip_whitespaces(p);
508 char ch = peekchar(p);
509 if (ch == '}') {
510 skipchar(p);
511 p->curdepth--;
512 return;
513 }
514 for (;;) {
515 parser_expect_char(p, '"');
516 parser_process_string(p); // key
517 ON_BEGIN_PAIR(p->ud, p->buff.b, p->buff.sz);
518
519 parser_skip_whitespaces(p);
520 parser_expect_char(p, ':');
521
522 parser_process_value(p); // value
523 ON_END_PAIR(p->ud);
524
525 parser_skip_whitespaces(p);
526 if (peekchar(p) == '}') {
527 skipchar(p);
528 p->curdepth--;
529 return;
530 }
531 else {
532 parser_expect_char(p, ',');
533 parser_skip_whitespaces(p);
534 }
535 }
536}
537
538static inline void parser_process_array(json_parser_t *p) {
539 parser_add_depth(p);
540 ON_ADD_ARRAY(p->ud);
541 parser_skip_whitespaces(p);
542 char ch = peekchar(p);
543 if (ch == ']') {
544 skipchar(p);
545 p->curdepth--;
546 return;
547 }
548 int i;
549 for (i = 0; ;++i) {
550 parser_process_value(p);
551 ON_ADD_INDEX(p->ud, i);
552
553 parser_skip_whitespaces(p);
554 if (peekchar(p) == ']') {
555 skipchar(p);
556 p->curdepth--;
557 return;
558 }
559 else {
560 parser_expect_char(p, ',');
561 }
562 }
563}
564
565static void parser_process_value(json_parser_t *p) {
566 parser_skip_whitespaces(p);
567 char ch = get_and_next(p);
568 switch (ch) {
569 case 'f':
570 parser_process_false(p);
571 break;
572 case 't':
573 parser_process_true(p);
574 break;
575 case 'n':
576 parser_process_null(p);
577 break;
578 case '"':
579 parser_process_string(p);
580 ON_ADD_STRING(p->ud, p->buff.b, p->buff.sz);
581 break;
582 case '{':
583 parser_process_object(p);
584 break;
585 case '[':
586 parser_process_array(p);
587 break;
588 default:
589 parser_process_number(p, ch);
590 break;
591 }
592}
593
594// 解析json文本
595static void parser_do_parse(const char *str, size_t size, void *ud, int maxdepth, int allowcomment) {
596 json_parser_t p;
597 parser_init(&p, str, size, ud, maxdepth, allowcomment);
598 //>>>if (setjmp(p.jb) == 0) {
599 parser_process_value(&p);
600 parser_skip_whitespaces(&p);
601 if (peekchar(&p) != '\0') {
602 parser_throw_error(&p, "Expect '<eof>' but got '%c', at: %s[:%lu]", peekchar(&p),
603 parser_error_content(&p), currpos(&p));
604 }
605 parser_free(&p);
606 //>>>}
607}
608
609//-----------------------------------------------------------------------------
610// dumpper
611
612typedef struct {
613 membuffer_t buff; // 临时缓存
614 int maxdepth; // 最大层次
615 int format; // 是否格式化
616 int empty_as_array; // 空表是否当成数组
617 int num_as_str; // 数字Key转为字符串
618 char errmsg[ERRMSG_SIZE]; // 保存错误消息
619} json_dumpper_t;
620
621// 足够转换数字的缓存大小
622#define NUMBER_BUFF_SZ 44
623#define INTEGER_BUFF_SZ 24
624
625// 抛出错误
626static void dumpper_throw_error(json_dumpper_t *d, lua_State *L, const char *fmt, ...) {
627 membuffer_free(&d->buff);
628 va_list arg;
629 va_start(arg, fmt);
630 vsnprintf(d->errmsg, ERRMSG_SIZE, fmt, arg);
631 va_end(arg);
632 luaL_error(L, d->errmsg);
633}
634
635static void dumpper_process_integer(json_dumpper_t *d, lua_State *L, int idx) {
636 char nbuff[INTEGER_BUFF_SZ];
637 int i = INTEGER_BUFF_SZ;
638 membuffer_ensure_space(&d->buff, INTEGER_BUFF_SZ);
639 int64_t x = (int64_t)lua_tointeger(L, idx);
640 uint64_t ux = (uint64_t)x;
641 if (x < 0) {
642 membuffer_putc_unsafe(&d->buff, '-');
643 ux = ~ux + 1;
644 }
645 do {
646 nbuff[--i] = (ux % 10) + '0';
647 } while (ux /= 10);
648 membuffer_putb_unsafe(&d->buff, nbuff+i, INTEGER_BUFF_SZ-i);
649}
650
651static void dumpper_process_number(json_dumpper_t *d, lua_State *L, int idx) {
652 lua_Number num = lua_tonumber(L, idx);
653 if (isinf(num) || isnan(num))
654 dumpper_throw_error(d, L, "The number is NaN or Infinity");
655 membuffer_ensure_space(&d->buff, NUMBER_BUFF_SZ);
656 char *p = membuffer_getp(&d->buff);
657 int len = sprintf(p, LUA_NUMBER_FMT, num);
658 membuffer_add_size(&d->buff, len);
659}
660
661// 字符转义表
662static const char char2escape[256] = {
663 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', 'u', 'u', 'u', 'u', // 0~19
664 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 0, 0, '"', 0, 0, 0, 0, 0, // 20~39
665 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40~59
666 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60~79
667 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0, 0, 0, 0, 0, // 80~99
668 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100~119
669 0, 0, 0, 0, 0, 0, 0, 'u', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120~139
670 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140~159
671 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160~179
672 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180~199
673 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200~219
674 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220~239
675 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240~256
676};
677static const char hex_digits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
678
679static void dumpper_process_string(json_dumpper_t *d, lua_State *L, int idx) {
680 membuffer_t *buff = &d->buff;
681 size_t len, i;
682 const char *str = lua_tolstring(L, idx, &len);
683 membuffer_ensure_space(buff, len * 6 + 2);
684 membuffer_putc_unsafe(buff, '\"');
685 char esc;
686 unsigned char ch;
687 for (i = 0; i < len; ++i) {
688 ch = (unsigned char)str[i];
689 esc = char2escape[ch];
690 if (likely(!esc))
691 membuffer_putc_unsafe(buff, (char)ch);
692 else {
693 membuffer_putc_unsafe(buff, '\\');
694 membuffer_putc_unsafe(buff, esc);
695 if (esc == 'u') {
696 membuffer_putc_unsafe(buff, '0');
697 membuffer_putc_unsafe(buff, '0');
698 membuffer_putc_unsafe(buff, hex_digits[(unsigned char)esc >> 4]);
699 membuffer_putc_unsafe(buff, hex_digits[(unsigned char)esc & 0xF]);
700 }
701 }
702 }
703 membuffer_putc_unsafe(buff, '\"');
704}
705
706static void dumpper_process_value(json_dumpper_t *d, lua_State *L, int depth);
707
708static int dumpper_check_array(json_dumpper_t *d, lua_State *L, int *len) {
709 int asize = lua_rawlen(L, -1);
710 if (asize > 0) {
711 lua_pushinteger(L, asize);
712 if (lua_next(L, -2) == 0) {
713 *len = asize;
714 return 1;
715 } else {
716 lua_pop(L, 2);
717 return 0;
718 }
719 } else {
720 lua_pushnil(L);
721 if (lua_next(L, -2) == 0) {
722 *len = asize;
723 return d->empty_as_array;
724 } else {
725 lua_pop(L, 2);
726 return 0;
727 }
728 }
729}
730
731static inline void dumpper_add_indent(json_dumpper_t *d, int count) {
732 membuffer_ensure_space(&d->buff, count);
733 int i;
734 for (i = 0; i < count; ++i)
735 membuffer_putc_unsafe(&d->buff, '\t');
736}
737
738static void dumpper_process_array(json_dumpper_t *d, lua_State *L, int len, int depth) {
739 membuffer_t *buff = &d->buff;
740 membuffer_putc(buff, '[');
741
742 int i;
743 for (i = 1; i <= len; ++i) {
744 if (unlikely(d->format && i == 1)) membuffer_putc(buff, '\n');
745 lua_rawgeti(L, -1, i);
746 if (unlikely(d->format)) dumpper_add_indent(d, depth);
747 dumpper_process_value(d, L, depth);
748 lua_pop(L, 1);
749 if (i < len)
750 membuffer_putc(buff, ',');
751 if (unlikely(d->format)) membuffer_putc(buff, '\n');
752 }
753
754 if (unlikely(d->format && i > 1)) dumpper_add_indent(d, depth-1);
755 membuffer_putc(buff, ']');
756}
757
758static void dumpper_process_object(json_dumpper_t *d, lua_State *L, int depth) {
759 membuffer_t *buff = &d->buff;
760 membuffer_putc(buff, '{');
761
762 int ktp;
763 int comma = 0;
764 lua_pushnil(L); // t nil
765 while (lua_next(L, -2) != 0) { // t k v
766 if (comma) {
767 membuffer_putc(buff, ',');
768 if (unlikely(d->format)) membuffer_putc(buff, '\n');
769 } else {
770 comma = 1;
771 if (unlikely(d->format)) membuffer_putc(buff, '\n');
772 }
773 // key
774 ktp = lua_type(L, -2);
775 if (ktp == LUA_TSTRING) {
776 if (unlikely(d->format)) dumpper_add_indent(d, depth);
777 dumpper_process_string(d, L, -2);
778 if (likely(!d->format))
779 membuffer_putc(buff, ':');
780 else
781 membuffer_putb(buff, " : ", 3);
782 } else if (ktp == LUA_TNUMBER && d->num_as_str) {
783 if (unlikely(d->format)) dumpper_add_indent(d, depth);
784 membuffer_putc(buff, '\"');
785 if (lua_isinteger(L, -2))
786 dumpper_process_integer(d, L, -2);
787 else
788 dumpper_process_number(d, L, -2);
789 if (likely(!d->format))
790 membuffer_putb(buff, "\":", 2);
791 else
792 membuffer_putb(buff, "\" : ", 4);
793 } else {
794 dumpper_throw_error(d, L, "Table key must be a string");
795 }
796 // value
797 dumpper_process_value(d, L, depth);
798 lua_pop(L, 1);
799 }
800 if (unlikely(d->format && comma)) {
801 membuffer_putc(buff, '\n');
802 dumpper_add_indent(d, depth-1);
803 }
804 membuffer_putc(buff, '}');
805}
806
807static inline void dumpper_process_table(json_dumpper_t *d, lua_State *L, int depth) {
808 depth++;
809 if (depth > d->maxdepth)
810 dumpper_throw_error(d, L, "Too many nested data, max depth is %d", d->maxdepth);
811 luaL_checkstack(L, 6, NULL);
812
813 int len;
814 if (dumpper_check_array(d, L, &len))
815 dumpper_process_array(d, L, len, depth);
816 else
817 dumpper_process_object(d, L, depth);
818}
819
820static void dumpper_process_value(json_dumpper_t *d, lua_State *L, int depth) {
821 int tp = lua_type(L, -1);
822 switch (tp) {
823 case LUA_TSTRING:
824 dumpper_process_string(d, L, -1);
825 break;
826 case LUA_TNUMBER:
827 if (lua_isinteger(L, -1))
828 dumpper_process_integer(d, L, -1);
829 else
830 dumpper_process_number(d, L, -1);
831 break;
832 case LUA_TBOOLEAN:
833 if (lua_toboolean(L, -1))
834 membuffer_putb(&d->buff, "true", 4);
835 else
836 membuffer_putb(&d->buff, "false", 5);
837 break;
838 case LUA_TTABLE:
839 dumpper_process_table(d, L, depth);
840 break;
841 case LUA_TNIL:
842 membuffer_putb(&d->buff, "null", 4);
843 break;
844 case LUA_TLIGHTUSERDATA:
845 if (lua_touserdata(L, -1) == NULL) {
846 membuffer_putb(&d->buff, "null", 4);
847 break;
848 }
849 goto error;
850 default:
851 error:
852 dumpper_throw_error(d, L, "Unsupport type %s", lua_typename(L, tp));
853 }
854}
855
856//-----------------------------------------------------------------------------
857// 接口
858#define DEF_MAX_DEPTH 128
859
860// 从字符串加载:json.load(str, maxdepth) -> obj
861// 要求字符串必须以0结尾
862int colibc_json_load(lua_State *L) {
863 size_t size;
864 const char *str = luaL_checklstring(L, 1, &size);
865 int maxdepth = (int)luaL_optinteger(L, 2, DEF_MAX_DEPTH);
866 int allowcomment = lua_toboolean(L, 3);
867 parser_do_parse(str, size, L, maxdepth, allowcomment);
868 return 1;
869}
870
871// 保存到字符串: json.dump(obj) -> str
872int colibc_json_dump(lua_State *L) {
873 luaL_checkany(L, 1);
874 json_dumpper_t dumpper;
875 membuffer_init(&dumpper.buff);
876 dumpper.format = lua_toboolean(L, 2);
877 dumpper.empty_as_array = lua_toboolean(L, 3);
878 dumpper.num_as_str = lua_toboolean(L, 4);
879 dumpper.maxdepth = (int)luaL_optinteger(L, 5, DEF_MAX_DEPTH);
880
881 lua_settop(L, 1);
882 dumpper_process_value(&dumpper, L, 0);
883 lua_pushlstring(L, dumpper.buff.b, dumpper.buff.sz);
884 membuffer_free(&dumpper.buff);
885 return 1;
886}
887
888static const luaL_Reg lib[] = {
889 {"load", colibc_json_load},
890 {"dump", colibc_json_dump},
891 {NULL, NULL},
892};
893
894LUAMOD_API int luaopen_colibc_json(lua_State *L) {
895 luaL_newlib(L, lib);
896 // json.null
897 lua_pushlightuserdata(L, NULL);
898 lua_setfield(L, -2, "null");
899 return 1;
900}
diff --git a/src/yue.cpp b/src/yue.cpp
index 2c3a469..aebc31d 100644
--- a/src/yue.cpp
+++ b/src/yue.cpp
@@ -72,18 +72,26 @@ extern "C" {
72#include "lua.h" 72#include "lua.h"
73#include "lualib.h" 73#include "lualib.h"
74int luaopen_yue(lua_State* L); 74int luaopen_yue(lua_State* L);
75int luaopen_colibc_json(lua_State* L);
75} // extern "C" 76} // extern "C"
76 77
77static void openlibs(void* state) { 78static void openlibs(void* state) {
78 lua_State* L = static_cast<lua_State*>(state); 79 lua_State* L = static_cast<lua_State*>(state);
79 luaL_openlibs(L); 80 luaL_openlibs(L);
81 int top = lua_gettop(L);
80#if LUA_VERSION_NUM > 501 82#if LUA_VERSION_NUM > 501
81 luaL_requiref(L, "yue", luaopen_yue, 0); 83 luaL_requiref(L, "yue", luaopen_yue, 0);
84 luaL_requiref(L, "json", luaopen_colibc_json, 0);
82#else 85#else
83 lua_pushcfunction(L, luaopen_yue); 86 lua_pushcfunction(L, luaopen_yue);
84 lua_call(L, 0, 0); 87 lua_call(L, 0, 0);
88 lua_getglobal(L, "package"); // package
89 lua_getfield(L, -1, "loaded"); // package loaded
90 lua_pushcfunction(L, luaopen_colibc_json);
91 lua_call(L, 0, 1); // package loaded json
92 lua_setfield(L, -2, "json"); // loaded["json"] = json, package loaded
85#endif 93#endif
86 lua_pop(L, 1); 94 lua_settop(L, top);
87} 95}
88 96
89void pushYue(lua_State* L, std::string_view name) { 97void pushYue(lua_State* L, std::string_view name) {