{unquoted_keys, true | false} now allows control of whether unquoted object keys are rejected or not by the parser/eep0018 decoder
This commit is contained in:
parent
b73e506fe2
commit
098fcbab1e
3 changed files with 61 additions and 0 deletions
|
@ -32,6 +32,7 @@
|
||||||
-record(opts, {
|
-record(opts, {
|
||||||
comments = false,
|
comments = false,
|
||||||
escaped_unicode = codepoint,
|
escaped_unicode = codepoint,
|
||||||
|
unquoted_keys = false,
|
||||||
multi_term = false,
|
multi_term = false,
|
||||||
encoding = auto
|
encoding = auto
|
||||||
}).
|
}).
|
||||||
|
@ -143,6 +144,9 @@ parse_opts([{comments, Value}|Rest], Opts) ->
|
||||||
parse_opts([{escaped_unicode, Value}|Rest], Opts) ->
|
parse_opts([{escaped_unicode, Value}|Rest], Opts) ->
|
||||||
true = lists:member(Value, [ascii, codepoint, none]),
|
true = lists:member(Value, [ascii, codepoint, none]),
|
||||||
parse_opts(Rest, Opts#opts{escaped_unicode=Value});
|
parse_opts(Rest, Opts#opts{escaped_unicode=Value});
|
||||||
|
parse_opts([{unquoted_keys, Value}|Rest], Opts) ->
|
||||||
|
true = lists:member(Value, [true, false]),
|
||||||
|
parse_opts(Rest, Opts#opts{unquoted_keys=Value});
|
||||||
parse_opts([{multi_term, Value}|Rest], Opts) ->
|
parse_opts([{multi_term, Value}|Rest], Opts) ->
|
||||||
true = lists:member(Value, [true, false]),
|
true = lists:member(Value, [true, false]),
|
||||||
parse_opts(Rest, Opts#opts{multi_term=Value});
|
parse_opts(Rest, Opts#opts{multi_term=Value});
|
||||||
|
@ -247,6 +251,9 @@ object(<<?end_object/?utfx, Rest/binary>>, [key|Stack], Opts) ->
|
||||||
{event, end_object, fun() -> maybe_done(Rest, Stack, Opts) end};
|
{event, end_object, fun() -> maybe_done(Rest, Stack, Opts) end};
|
||||||
object(<<?solidus/?utfx, Rest/binary>>, Stack, #opts{comments=true}=Opts) ->
|
object(<<?solidus/?utfx, Rest/binary>>, Stack, #opts{comments=true}=Opts) ->
|
||||||
maybe_comment(Rest, fun(Resume) -> object(Resume, Stack, Opts) end);
|
maybe_comment(Rest, fun(Resume) -> object(Resume, Stack, Opts) end);
|
||||||
|
object(<<S/?utfx, Rest/binary>>, Stack, #opts{unquoted_keys=true}=Opts)
|
||||||
|
when ?is_noncontrol(S) ->
|
||||||
|
unquoted_key(Rest, Stack, Opts, [S]);
|
||||||
object(Bin, Stack, Opts) ->
|
object(Bin, Stack, Opts) ->
|
||||||
case ?partial_codepoint(Bin) of
|
case ?partial_codepoint(Bin) of
|
||||||
true ->
|
true ->
|
||||||
|
@ -353,6 +360,9 @@ key(<<?quote/?utfx, Rest/binary>>, Stack, Opts) ->
|
||||||
string(Rest, Stack, Opts, []);
|
string(Rest, Stack, Opts, []);
|
||||||
key(<<?solidus/?utfx, Rest/binary>>, Stack, #opts{comments=true}=Opts) ->
|
key(<<?solidus/?utfx, Rest/binary>>, Stack, #opts{comments=true}=Opts) ->
|
||||||
maybe_comment(Rest, fun(Resume) -> key(Resume, Stack, Opts) end);
|
maybe_comment(Rest, fun(Resume) -> key(Resume, Stack, Opts) end);
|
||||||
|
key(<<S/?utfx, Rest/binary>>, Stack, #opts{unquoted_keys=true}=Opts)
|
||||||
|
when ?is_noncontrol(S) ->
|
||||||
|
unquoted_key(Rest, Stack, Opts, [S]);
|
||||||
key(Bin, Stack, Opts) ->
|
key(Bin, Stack, Opts) ->
|
||||||
case ?partial_codepoint(Bin) of
|
case ?partial_codepoint(Bin) of
|
||||||
true ->
|
true ->
|
||||||
|
@ -365,6 +375,33 @@ key(Bin, Stack, Opts) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
unquoted_key(<<S/?utfx, Rest/binary>>, Stack, Opts, Acc)
|
||||||
|
when ?is_whitespace(S) ->
|
||||||
|
{event, {key, lists:reverse(Acc)}, fun() -> colon(Rest, Stack, Opts) end};
|
||||||
|
unquoted_key(<<?colon/?utfx, Rest/binary>>, [key|Stack], Opts, Acc) ->
|
||||||
|
{event,
|
||||||
|
{key, lists:reverse(Acc)},
|
||||||
|
fun() -> value(Rest, [object|Stack], Opts) end
|
||||||
|
};
|
||||||
|
unquoted_key(<<S/?utfx, Rest/binary>>, Stack, Opts, Acc)
|
||||||
|
when ?is_noncontrol(S) ->
|
||||||
|
unquoted_key(Rest, Stack, Opts, [S] ++ Acc);
|
||||||
|
unquoted_key(Bin, Stack, Opts, Acc) ->
|
||||||
|
case partial_utf(Bin) of
|
||||||
|
true ->
|
||||||
|
{incomplete, fun(end_stream) ->
|
||||||
|
{error, badjson}
|
||||||
|
; (Stream) ->
|
||||||
|
unquoted_key(<<Bin/binary, Stream/binary>>,
|
||||||
|
Stack,
|
||||||
|
Opts,
|
||||||
|
Acc
|
||||||
|
)
|
||||||
|
end}
|
||||||
|
; false -> {error, badjson}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
%% string has an additional parameter, an accumulator (Acc) used to hold the
|
%% string has an additional parameter, an accumulator (Acc) used to hold the
|
||||||
%% intermediate representation of the string being parsed. using a list of
|
%% intermediate representation of the string being parsed. using a list of
|
||||||
%% integers representing unicode codepoints is faster than constructing
|
%% integers representing unicode codepoints is faster than constructing
|
||||||
|
|
1
test/cases/object_with_unquoted_keys.json
Normal file
1
test/cases/object_with_unquoted_keys.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{foo : "bar", baz:true, false : null,object:{ key : "value" },list:[null,null,null,[],"\n\r\\"]}
|
23
test/cases/object_with_unquoted_keys.test
Normal file
23
test/cases/object_with_unquoted_keys.test
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{name, "object with unquoted keys"}.
|
||||||
|
{jsx, [start_object,
|
||||||
|
{key,"foo"},
|
||||||
|
{string,"bar"},
|
||||||
|
{key,"baz"},
|
||||||
|
{literal,true},
|
||||||
|
{key,"false"},
|
||||||
|
{literal,null},
|
||||||
|
{key,"object"},
|
||||||
|
start_object,
|
||||||
|
{key,"key"},
|
||||||
|
{string,"value"},
|
||||||
|
end_object,
|
||||||
|
{key,"list"},
|
||||||
|
start_array,
|
||||||
|
{literal,null},
|
||||||
|
{literal,null},
|
||||||
|
{literal,null},
|
||||||
|
start_array,end_array,
|
||||||
|
{string,"\n\r\\"},
|
||||||
|
end_array,end_object,end_json]}.
|
||||||
|
{json, "object_with_unquoted_keys.json"}.
|
||||||
|
{jsx_flags, [{unquoted_keys, true}]}.
|
Loading…
Add table
Add a link
Reference in a new issue