Drop non-standard JSON extension
Ref: https://github.com/quickjs-ng/quickjs/issues/20
This commit is contained in:
parent
5d5b3cc21f
commit
c1ed688610
5 changed files with 10 additions and 143 deletions
|
@ -451,20 +451,6 @@ optional properties:
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@item parseExtJSON(str)
|
|
||||||
|
|
||||||
Parse @code{str} using a superset of @code{JSON.parse}. The
|
|
||||||
following extensions are accepted:
|
|
||||||
|
|
||||||
@itemize
|
|
||||||
@item Single line and multiline comments
|
|
||||||
@item unquoted properties (ASCII-only Javascript identifiers)
|
|
||||||
@item trailing comma in array and object definitions
|
|
||||||
@item single quoted strings
|
|
||||||
@item @code{\f} and @code{\v} are accepted as space characters
|
|
||||||
@item leading plus in numbers
|
|
||||||
@item octal (@code{0o} prefix) and hexadecimal (@code{0x} prefix) numbers
|
|
||||||
@end itemize
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
FILE prototype:
|
FILE prototype:
|
||||||
|
|
|
@ -822,21 +822,6 @@ static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,
|
||||||
return JS_NewString(ctx, strerror(err));
|
return JS_NewString(ctx, strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue js_std_parseExtJSON(JSContext *ctx, JSValueConst this_val,
|
|
||||||
int argc, JSValueConst *argv)
|
|
||||||
{
|
|
||||||
JSValue obj;
|
|
||||||
const char *str;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
str = JS_ToCStringLen(ctx, &len, argv[0]);
|
|
||||||
if (!str)
|
|
||||||
return JS_EXCEPTION;
|
|
||||||
obj = JS_ParseJSON2(ctx, str, len, "<input>", JS_PARSE_JSON_EXT);
|
|
||||||
JS_FreeCString(ctx, str);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
static JSValue js_new_std_file(JSContext *ctx, FILE *f,
|
static JSValue js_new_std_file(JSContext *ctx, FILE *f,
|
||||||
BOOL close_in_finalizer,
|
BOOL close_in_finalizer,
|
||||||
BOOL is_popen)
|
BOOL is_popen)
|
||||||
|
@ -1492,7 +1477,6 @@ static const JSCFunctionListEntry js_std_funcs[] = {
|
||||||
JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
|
JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
|
||||||
JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
|
JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
|
||||||
JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
|
JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
|
||||||
JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ),
|
|
||||||
|
|
||||||
/* FILE I/O */
|
/* FILE I/O */
|
||||||
JS_CFUNC_DEF("open", 2, js_std_open ),
|
JS_CFUNC_DEF("open", 2, js_std_open ),
|
||||||
|
|
103
quickjs.c
103
quickjs.c
|
@ -19464,7 +19464,6 @@ typedef struct JSParseState {
|
||||||
JSFunctionDef *cur_func;
|
JSFunctionDef *cur_func;
|
||||||
BOOL is_module; /* parsing a module */
|
BOOL is_module; /* parsing a module */
|
||||||
BOOL allow_html_comments;
|
BOOL allow_html_comments;
|
||||||
BOOL ext_json; /* true if accepting JSON superset */
|
|
||||||
} JSParseState;
|
} JSParseState;
|
||||||
|
|
||||||
typedef struct JSOpCode {
|
typedef struct JSOpCode {
|
||||||
|
@ -20563,11 +20562,8 @@ static __exception int json_next_token(JSParseState *s)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '\'':
|
case '\'':
|
||||||
if (!s->ext_json) {
|
/* JSON does not accept single quoted strings */
|
||||||
/* JSON does not accept single quoted strings */
|
goto def_token;
|
||||||
goto def_token;
|
|
||||||
}
|
|
||||||
/* fall through */
|
|
||||||
case '\"':
|
case '\"':
|
||||||
if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
|
if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -20583,72 +20579,15 @@ static __exception int json_next_token(JSParseState *s)
|
||||||
goto redo;
|
goto redo;
|
||||||
case '\f':
|
case '\f':
|
||||||
case '\v':
|
case '\v':
|
||||||
if (!s->ext_json) {
|
/* JSONWhitespace does not match <VT>, nor <FF> */
|
||||||
/* JSONWhitespace does not match <VT>, nor <FF> */
|
goto def_token;
|
||||||
goto def_token;
|
|
||||||
}
|
|
||||||
/* fall through */
|
|
||||||
case ' ':
|
case ' ':
|
||||||
case '\t':
|
case '\t':
|
||||||
p++;
|
p++;
|
||||||
goto redo;
|
goto redo;
|
||||||
case '/':
|
case '/':
|
||||||
if (!s->ext_json) {
|
/* JSON does not accept comments */
|
||||||
/* JSON does not accept comments */
|
goto def_token;
|
||||||
goto def_token;
|
|
||||||
}
|
|
||||||
if (p[1] == '*') {
|
|
||||||
/* comment */
|
|
||||||
p += 2;
|
|
||||||
for(;;) {
|
|
||||||
if (*p == '\0' && p >= s->buf_end) {
|
|
||||||
js_parse_error(s, "unexpected end of comment");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (p[0] == '*' && p[1] == '/') {
|
|
||||||
p += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (*p == '\n') {
|
|
||||||
s->line_num++;
|
|
||||||
p++;
|
|
||||||
} else if (*p == '\r') {
|
|
||||||
p++;
|
|
||||||
} else if (*p >= 0x80) {
|
|
||||||
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
|
|
||||||
if (c == -1) {
|
|
||||||
p++; /* skip invalid UTF-8 */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto redo;
|
|
||||||
} else if (p[1] == '/') {
|
|
||||||
/* line comment */
|
|
||||||
p += 2;
|
|
||||||
for(;;) {
|
|
||||||
if (*p == '\0' && p >= s->buf_end)
|
|
||||||
break;
|
|
||||||
if (*p == '\r' || *p == '\n')
|
|
||||||
break;
|
|
||||||
if (*p >= 0x80) {
|
|
||||||
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
|
|
||||||
/* LS or PS are considered as line terminator */
|
|
||||||
if (c == CP_LS || c == CP_PS) {
|
|
||||||
break;
|
|
||||||
} else if (c == -1) {
|
|
||||||
p++; /* skip invalid UTF-8 */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto redo;
|
|
||||||
} else {
|
|
||||||
goto def_token;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'a': case 'b': case 'c': case 'd':
|
case 'a': case 'b': case 'c': case 'd':
|
||||||
case 'e': case 'f': case 'g': case 'h':
|
case 'e': case 'f': case 'g': case 'h':
|
||||||
case 'i': case 'j': case 'k': case 'l':
|
case 'i': case 'j': case 'k': case 'l':
|
||||||
|
@ -20676,7 +20615,7 @@ static __exception int json_next_token(JSParseState *s)
|
||||||
s->token.val = TOK_IDENT;
|
s->token.val = TOK_IDENT;
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
if (!s->ext_json || !is_digit(p[1]))
|
if (!is_digit(p[1]))
|
||||||
goto def_token;
|
goto def_token;
|
||||||
goto parse_number;
|
goto parse_number;
|
||||||
case '0':
|
case '0':
|
||||||
|
@ -20693,17 +20632,7 @@ static __exception int json_next_token(JSParseState *s)
|
||||||
/* number */
|
/* number */
|
||||||
parse_number:
|
parse_number:
|
||||||
{
|
{
|
||||||
JSValue ret;
|
JSValue ret = js_atof(s->ctx, (const char *)p, (const char **)&p, 10, 0);
|
||||||
int flags, radix;
|
|
||||||
if (!s->ext_json) {
|
|
||||||
flags = 0;
|
|
||||||
radix = 10;
|
|
||||||
} else {
|
|
||||||
flags = ATOD_ACCEPT_BIN_OCT;
|
|
||||||
radix = 0;
|
|
||||||
}
|
|
||||||
ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
|
|
||||||
flags);
|
|
||||||
if (JS_IsException(ret))
|
if (JS_IsException(ret))
|
||||||
goto fail;
|
goto fail;
|
||||||
s->token.val = TOK_NUMBER;
|
s->token.val = TOK_NUMBER;
|
||||||
|
@ -42935,8 +42864,6 @@ static JSValue json_parse_value(JSParseState *s)
|
||||||
prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
|
prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
|
||||||
if (prop_name == JS_ATOM_NULL)
|
if (prop_name == JS_ATOM_NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (s->ext_json && s->token.val == TOK_IDENT) {
|
|
||||||
prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
|
|
||||||
} else {
|
} else {
|
||||||
js_parse_error(s, "expecting property name");
|
js_parse_error(s, "expecting property name");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -42961,8 +42888,6 @@ static JSValue json_parse_value(JSParseState *s)
|
||||||
break;
|
break;
|
||||||
if (json_next_token(s))
|
if (json_next_token(s))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (s->ext_json && s->token.val == '}')
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (json_parse_expect(s, '}'))
|
if (json_parse_expect(s, '}'))
|
||||||
|
@ -42993,8 +42918,6 @@ static JSValue json_parse_value(JSParseState *s)
|
||||||
if (json_next_token(s))
|
if (json_next_token(s))
|
||||||
goto fail;
|
goto fail;
|
||||||
idx++;
|
idx++;
|
||||||
if (s->ext_json && s->token.val == ']')
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (json_parse_expect(s, ']'))
|
if (json_parse_expect(s, ']'))
|
||||||
|
@ -43039,14 +42962,12 @@ static JSValue json_parse_value(JSParseState *s)
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
|
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, const char *filename)
|
||||||
const char *filename, int flags)
|
|
||||||
{
|
{
|
||||||
JSParseState s1, *s = &s1;
|
JSParseState s1, *s = &s1;
|
||||||
JSValue val = JS_UNDEFINED;
|
JSValue val = JS_UNDEFINED;
|
||||||
|
|
||||||
js_parse_init(ctx, s, buf, buf_len, filename);
|
js_parse_init(ctx, s, buf, buf_len, filename);
|
||||||
s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
|
|
||||||
if (json_next_token(s))
|
if (json_next_token(s))
|
||||||
goto fail;
|
goto fail;
|
||||||
val = json_parse_value(s);
|
val = json_parse_value(s);
|
||||||
|
@ -43063,12 +42984,6 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
|
||||||
const char *filename)
|
|
||||||
{
|
|
||||||
return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
|
static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
|
||||||
JSAtom name, JSValueConst reviver)
|
JSAtom name, JSValueConst reviver)
|
||||||
{
|
{
|
||||||
|
|
|
@ -777,9 +777,6 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id);
|
||||||
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
|
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
|
||||||
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
#define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */
|
|
||||||
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
|
|
||||||
const char *filename, int flags);
|
|
||||||
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
|
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
|
||||||
JSValueConst replacer, JSValueConst space0);
|
JSValueConst replacer, JSValueConst space0);
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ function test_getline()
|
||||||
|
|
||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_popen()
|
function test_popen()
|
||||||
{
|
{
|
||||||
var str, f, fname = "tmp_file.txt";
|
var str, f, fname = "tmp_file.txt";
|
||||||
|
@ -127,20 +127,6 @@ function test_popen()
|
||||||
os.remove(fname);
|
os.remove(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_ext_json()
|
|
||||||
{
|
|
||||||
var expected, input, obj;
|
|
||||||
expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"s":"str"}';
|
|
||||||
input = `{ "x":false, /*comments are allowed */
|
|
||||||
"y":true, // also a comment
|
|
||||||
z2:null, // unquoted property names
|
|
||||||
"a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal
|
|
||||||
"s":"str",} // trailing comma in objects and arrays
|
|
||||||
`;
|
|
||||||
obj = std.parseExtJSON(input);
|
|
||||||
assert(JSON.stringify(obj), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_os()
|
function test_os()
|
||||||
{
|
{
|
||||||
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
|
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
|
||||||
|
@ -283,4 +269,3 @@ test_popen();
|
||||||
test_os();
|
test_os();
|
||||||
!isWin && test_os_exec();
|
!isWin && test_os_exec();
|
||||||
test_timer();
|
test_timer();
|
||||||
test_ext_json();
|
|
||||||
|
|
Loading…
Reference in a new issue