Elixir needs at least 4 JSON parsers
Elixir has, at the time of this post, 3 JSON parsers hosted on expm.
Some time back I went looking for one and started exploring elixir-json, including the github repo. I loved how the encoder used protocols to implement the encoding of different types. It’s beautiful. Kudos to @carloslage.
Then I looked at the decoder. It’s full of elixir-isms… tuples, binary pattern matching, etc. Over the last few nights I decided to implement my own JSON parser learning from Carlos were I ran aground.
I don’t like the use of HashDict for objects, but spaces rule out most options like Keyword lists. I’m also not a huge fan of the nested case for dealing with the what’s next? of key/value pairs.
def parse_object( acc, << rest :: binary >> ) do
{ key, rest } = parse_content rest
{ value, rest } = lstrip(rest) |> parse_object_value
acc = [ { key, value } | acc ]
case lstrip(rest) do
<< ?}, rest :: binary >> -> { HashDict.new(acc), rest }
<< ?,, rest :: binary >> -> parse_object acc, lstrip(rest)
end
end
Overall it feels very cohesive. You can see clearly how the pieces compose after being dispatched from the parse_content.
def parse_content( << m, rest :: binary >> ) when m in ?0..?9, do: parse_number << m, rest :: binary >>
def parse_content( << ?", rest :: binary >> ), do: rest |> parse_string
def parse_content( << ?{, rest :: binary >> ), do: lstrip(rest) |> parse_object
def parse_content( << ?[, rest :: binary >> ), do: lstrip(rest) |> parse_array
I also do nothing to support invalid JSON content as with elixir-json. Oh well, it was a learning tool.
Recovered from the Wayback Machine.