Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -module(json).
- -export([parse/1,test/1]).
- %-compile(export_all)
- test(String) ->
- io:format("Parsing ~p:~n",[String]),
- Parsed = parse(String),
- io:format("~tp~n-----~n",[Parsed]).
- parse(String) ->
- {Parsed, []} = parse_thing(String),
- Parsed.
- is_whitespace(Ch) ->
- Ch =< 32.
- skip_whitespaces([]) -> [];
- skip_whitespaces(String) ->
- [H | T] = String,
- case is_whitespace(H) of
- true -> skip_whitespaces(T);
- false -> String
- end.
- % Returns {Got, Rest}
- take_chars_while(Predicate, String) ->
- take_chars_while(Predicate, String, []).
- take_chars_while(_Pred, [], RevGot) ->
- {lists:reverse(RevGot), []};
- take_chars_while(Predicate, Remains, RevGot) ->
- [RemH | RemT] = Remains,
- case Predicate(RemH) of
- false ->
- {lists:reverse(RevGot), Remains};
- true ->
- take_chars_while(Predicate, RemT, [RemH | RevGot])
- end.
- % we are now past "[" and past whitespaces
- parse_array_after_paren(Rest, RevItems) ->
- case Rest of
- [$]|AfterEnd] ->
- {lists:reverse(RevItems), AfterEnd};
- _ ->
- {ArrayItem, AfterArrItem} = parse_thing(Rest),
- case AfterArrItem of
- [$]|RestAfterArray] ->
- {lists:reverse([ArrayItem | RevItems]), RestAfterArray};
- [$,|RestAfterComma] ->
- parse_array_after_paren(skip_whitespaces(RestAfterComma), [ArrayItem | RevItems])
- end
- end.
- % we are now past "{" and past whitespaces
- parse_object_after_paren(Rest, Map) ->
- case Rest of
- [$}|AfterEnd] ->
- {Map, AfterEnd};
- _ ->
- {MapKey, AfterMapKey} = parse_thing(Rest),
- [$:|AfterColon] = AfterMapKey,
- {MapValue, AfterMapValue} = parse_thing(AfterColon),
- NewMap = Map#{ binary_to_atom(MapKey) => MapValue },
- case AfterMapValue of
- [$}|RestAfterMap] ->
- {NewMap, RestAfterMap};
- [$,|RestAfterComma] ->
- parse_object_after_paren(skip_whitespaces(RestAfterComma), NewMap)
- end
- end.
- parse_string_after_quote(Rest) ->
- parse_string_after_quote(Rest, []).
- %todo more control characters, \r, \n etc...
- parse_string_after_quote([$"|AfterString], RevString) ->
- {unicode:characters_to_binary(lists:reverse(RevString)), AfterString};
- parse_string_after_quote([$\\,$"|Rest], RevString) ->
- parse_string_after_quote(Rest, [$"|RevString]);
- parse_string_after_quote([Char|Rest], RevString) ->
- parse_string_after_quote(Rest,[Char|RevString]).
- parse_number([$- | NumberAndRest]) ->
- {Parsed, Rest} = parse_number(NumberAndRest),
- {0 - Parsed, Rest};
- parse_number(NumberAndRest) ->
- {NumString, Rest} = take_chars_while(fun(Ch) -> not (is_whitespace(Ch) orelse lists:any(fun(X) -> X == Ch end,[$,, $], $}])) end, NumberAndRest),
- case string:to_integer(NumString) of
- {Integer, []} ->
- {Integer, Rest};
- _ ->
- {Float, []} = string:to_float(NumString),
- {Float, Rest}
- end.
- parse_thing(String) ->
- BeforeThing = skip_whitespaces(String),
- {Parsed, AfterThing} = parse_thing_without_whitespaces(BeforeThing),
- {Parsed, skip_whitespaces(AfterThing)}.
- % returns {ParsedThing, Rest}
- parse_thing_without_whitespaces("true" ++ Rest) ->
- {true, Rest};
- parse_thing_without_whitespaces("false" ++ Rest) ->
- {false, Rest};
- parse_thing_without_whitespaces("null" ++ Rest) ->
- {null, Rest};
- parse_thing_without_whitespaces([$[|Rest]) ->
- parse_array_after_paren(skip_whitespaces(Rest), []);
- parse_thing_without_whitespaces([${|Rest]) ->
- parse_object_after_paren(skip_whitespaces(Rest), #{});
- parse_thing_without_whitespaces([$"|AfterQuote]) ->
- parse_string_after_quote(AfterQuote);
- parse_thing_without_whitespaces (NumberAndRest) ->
- parse_number(NumberAndRest).
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement