Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop non-standard JSON extension #30

Merged
merged 1 commit into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions doc/quickjs.texi
Original file line number Diff line number Diff line change
Expand Up @@ -451,20 +451,6 @@ optional properties:

@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

FILE prototype:
Expand Down
16 changes: 0 additions & 16 deletions quickjs-libc.c
Original file line number Diff line number Diff line change
Expand Up @@ -822,21 +822,6 @@ static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,
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,
BOOL close_in_finalizer,
BOOL is_popen)
Expand Down Expand Up @@ -1492,7 +1477,6 @@ static const JSCFunctionListEntry js_std_funcs[] = {
JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ),

/* FILE I/O */
JS_CFUNC_DEF("open", 2, js_std_open ),
Expand Down
103 changes: 9 additions & 94 deletions quickjs.c
Original file line number Diff line number Diff line change
Expand Up @@ -19464,7 +19464,6 @@ typedef struct JSParseState {
JSFunctionDef *cur_func;
BOOL is_module; /* parsing a module */
BOOL allow_html_comments;
BOOL ext_json; /* true if accepting JSON superset */
} JSParseState;

typedef struct JSOpCode {
Expand Down Expand Up @@ -20563,11 +20562,8 @@ static __exception int json_next_token(JSParseState *s)
}
break;
case '\'':
if (!s->ext_json) {
/* JSON does not accept single quoted strings */
goto def_token;
}
/* fall through */
/* JSON does not accept single quoted strings */
goto def_token;
case '\"':
if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
goto fail;
Expand All @@ -20583,72 +20579,15 @@ static __exception int json_next_token(JSParseState *s)
goto redo;
case '\f':
case '\v':
if (!s->ext_json) {
/* JSONWhitespace does not match <VT>, nor <FF> */
goto def_token;
}
/* fall through */
/* JSONWhitespace does not match <VT>, nor <FF> */
goto def_token;
case ' ':
case '\t':
p++;
goto redo;
case '/':
if (!s->ext_json) {
/* JSON does not accept comments */
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;
/* JSON does not accept comments */
goto def_token;
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
Expand Down Expand Up @@ -20676,7 +20615,7 @@ static __exception int json_next_token(JSParseState *s)
s->token.val = TOK_IDENT;
break;
case '+':
if (!s->ext_json || !is_digit(p[1]))
if (!is_digit(p[1]))
goto def_token;
goto parse_number;
case '0':
Expand All @@ -20693,17 +20632,7 @@ static __exception int json_next_token(JSParseState *s)
/* number */
parse_number:
{
JSValue ret;
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);
JSValue ret = js_atof(s->ctx, (const char *)p, (const char **)&p, 10, 0);
if (JS_IsException(ret))
goto fail;
s->token.val = TOK_NUMBER;
Expand Down Expand Up @@ -42935,8 +42864,6 @@ static JSValue json_parse_value(JSParseState *s)
prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
if (prop_name == JS_ATOM_NULL)
goto fail;
} else if (s->ext_json && s->token.val == TOK_IDENT) {
prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
} else {
js_parse_error(s, "expecting property name");
goto fail;
Expand All @@ -42961,8 +42888,6 @@ static JSValue json_parse_value(JSParseState *s)
break;
if (json_next_token(s))
goto fail;
if (s->ext_json && s->token.val == '}')
break;
}
}
if (json_parse_expect(s, '}'))
Expand Down Expand Up @@ -42993,8 +42918,6 @@ static JSValue json_parse_value(JSParseState *s)
if (json_next_token(s))
goto fail;
idx++;
if (s->ext_json && s->token.val == ']')
break;
}
}
if (json_parse_expect(s, ']'))
Expand Down Expand Up @@ -43039,14 +42962,12 @@ static JSValue json_parse_value(JSParseState *s)
return JS_EXCEPTION;
}

JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
const char *filename, int flags)
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, const char *filename)
{
JSParseState s1, *s = &s1;
JSValue val = JS_UNDEFINED;

js_parse_init(ctx, s, buf, buf_len, filename);
s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
if (json_next_token(s))
goto fail;
val = json_parse_value(s);
Expand All @@ -43063,12 +42984,6 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
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,
JSAtom name, JSValueConst reviver)
{
Expand Down
3 changes: 0 additions & 3 deletions quickjs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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'. */
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
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,
JSValueConst replacer, JSValueConst space0);

Expand Down
17 changes: 1 addition & 16 deletions tests/test_std.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ function test_getline()

f.close();
}

function test_popen()
{
var str, f, fname = "tmp_file.txt";
Expand All @@ -127,20 +127,6 @@ function test_popen()
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()
{
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
Expand Down Expand Up @@ -283,4 +269,3 @@ test_popen();
test_os();
!isWin && test_os_exec();
test_timer();
test_ext_json();