Current section

Files

Jump to
gsv src gsv.erl
Raw

src/gsv.erl

-module(gsv).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([from_lists/3, from_dicts/3, to_lists/1, to_dicts/1]).
-export_type([parse_error/0, line_ending/0, parse_status/0]).
-type parse_error() :: {unescaped_quote, integer()} |
{unclosed_escaped_field, integer()}.
-type line_ending() :: windows | unix.
-type parse_status() :: parsing_escaped_field |
parsing_unescaped_field |
comma_found |
newline_found.
-file("/Users/benjamin/Personal/gsv/src/gsv.gleam", 46).
-spec line_ending_to_string(line_ending()) -> binary().
line_ending_to_string(Le) ->
case Le of
windows ->
<<"\r\n"/utf8>>;
unix ->
<<"\n"/utf8>>
end.
-file("/Users/benjamin/Personal/gsv/src/gsv.gleam", 406).
-spec escape_field(binary(), binary()) -> binary().
escape_field(Field, Separator) ->
case gleam_stdlib:contains_string(Field, <<"\""/utf8>>) of
true ->
<<<<"\""/utf8,
(gleam@string:replace(Field, <<"\""/utf8>>, <<"\"\""/utf8>>))/binary>>/binary,
"\""/utf8>>;
false ->
case gleam_stdlib:contains_string(Field, Separator) orelse gleam_stdlib:contains_string(
Field,
<<"\n"/utf8>>
) of
true ->
<<<<"\""/utf8, Field/binary>>/binary, "\""/utf8>>;
false ->
Field
end
end.
-file("/Users/benjamin/Personal/gsv/src/gsv.gleam", 391).
-spec from_lists(list(list(binary())), binary(), line_ending()) -> binary().
from_lists(Rows, Separator, Line_ending) ->
Line_ending@1 = line_ending_to_string(Line_ending),
_pipe@1 = gleam@list:map(
Rows,
fun(Row) ->
_pipe = gleam@list:map(
Row,
fun(_capture) -> escape_field(_capture, Separator) end
),
gleam@string:join(_pipe, Separator)
end
),
_pipe@2 = gleam@string:join(_pipe@1, Line_ending@1),
gleam@string:append(_pipe@2, Line_ending@1).
-file("/Users/benjamin/Personal/gsv/src/gsv.gleam", 443).
-spec row_dict_to_list(gleam@dict:dict(binary(), binary()), list(binary())) -> list(binary()).
row_dict_to_list(Row, Headers) ->
gleam@list:map(
Headers,
fun(Header) -> case gleam_stdlib:map_get(Row, Header) of
{ok, Field} ->
Field;
{error, nil} ->
<<""/utf8>>
end end
).
-file("/Users/benjamin/Personal/gsv/src/gsv.gleam", 423).
-spec from_dicts(
list(gleam@dict:dict(binary(), binary())),
binary(),
line_ending()
) -> binary().
from_dicts(Rows, Separator, Line_ending) ->
case Rows of
[] ->
<<""/utf8>>;
_ ->
Headers = begin
_pipe = Rows,
_pipe@1 = gleam@list:flat_map(_pipe, fun maps:keys/1),
_pipe@2 = gleam@list:unique(_pipe@1),
gleam@list:sort(_pipe@2, fun gleam@string:compare/2)
end,
Rows@1 = gleam@list:map(
Rows,
fun(_capture) -> row_dict_to_list(_capture, Headers) end
),
from_lists([Headers | Rows@1], Separator, Line_ending)
end.
-file("/Users/benjamin/Personal/gsv/src/gsv.gleam", 306).
-spec extract_field(binary(), integer(), integer(), parse_status()) -> binary().
extract_field(String, From, Length, Status) ->
Field = gsv_ffi:slice(String, From, Length),
case Status of
comma_found ->
Field;
parsing_unescaped_field ->
Field;
newline_found ->
Field;
parsing_escaped_field ->
gleam@string:replace(Field, <<"\"\""/utf8>>, <<"\""/utf8>>)
end.
-file("/Users/benjamin/Personal/gsv/src/gsv.gleam", 141).
-spec do_parse(
binary(),
binary(),
integer(),
integer(),
list(binary()),
list(list(binary())),
parse_status()
) -> {ok, list(list(binary()))} | {error, parse_error()}.
do_parse(String, Original, Field_start, Field_length, Row, Rows, Status) ->
case {String, Status} of
{<<","/utf8, Rest/binary>>, comma_found} ->
Field = extract_field(Original, Field_start, Field_length, Status),
Row@1 = [Field | Row],
Field_start@1 = (Field_start + Field_length) + 1,
do_parse(Rest, Original, Field_start@1, 0, Row@1, Rows, comma_found);
{<<","/utf8, Rest/binary>>, newline_found} ->
Field = extract_field(Original, Field_start, Field_length, Status),
Row@1 = [Field | Row],
Field_start@1 = (Field_start + Field_length) + 1,
do_parse(Rest, Original, Field_start@1, 0, Row@1, Rows, comma_found);
{<<","/utf8, Rest/binary>>, parsing_unescaped_field} ->
Field = extract_field(Original, Field_start, Field_length, Status),
Row@1 = [Field | Row],
Field_start@1 = (Field_start + Field_length) + 1,
do_parse(Rest, Original, Field_start@1, 0, Row@1, Rows, comma_found);
{<<"\","/utf8, Rest@1/binary>>, parsing_escaped_field} ->
Field@1 = extract_field(Original, Field_start, Field_length, Status),
Row@2 = [Field@1 | Row],
Field_start@2 = (Field_start + Field_length) + 2,
do_parse(
Rest@1,
Original,
Field_start@2,
0,
Row@2,
Rows,
comma_found
);
{<<""/utf8>>, parsing_unescaped_field} ->
Field@2 = extract_field(Original, Field_start, Field_length, Status),
Row@3 = lists:reverse([Field@2 | Row]),
{ok, lists:reverse([Row@3 | Rows])};
{<<"\""/utf8>>, parsing_escaped_field} ->
Field@2 = extract_field(Original, Field_start, Field_length, Status),
Row@3 = lists:reverse([Field@2 | Row]),
{ok, lists:reverse([Row@3 | Rows])};
{<<""/utf8>>, comma_found} ->
Row@4 = lists:reverse([<<""/utf8>> | Row]),
{ok, lists:reverse([Row@4 | Rows])};
{<<""/utf8>>, newline_found} ->
{ok, lists:reverse(Rows)};
{<<""/utf8>>, parsing_escaped_field} ->
{error, {unclosed_escaped_field, Field_start}};
{<<"\n"/utf8, Rest@2/binary>>, parsing_unescaped_field} ->
Field@3 = extract_field(Original, Field_start, Field_length, Status),
Row@5 = lists:reverse([Field@3 | Row]),
Rows@1 = [Row@5 | Rows],
Field_start@3 = (Field_start + Field_length) + 1,
do_parse(
Rest@2,
Original,
Field_start@3,
0,
[],
Rows@1,
newline_found
);
{<<"\r\n"/utf8, Rest@3/binary>>, parsing_unescaped_field} ->
Field@4 = extract_field(Original, Field_start, Field_length, Status),
Row@6 = lists:reverse([Field@4 | Row]),
Rows@2 = [Row@6 | Rows],
Field_start@4 = (Field_start + Field_length) + 2,
do_parse(
Rest@3,
Original,
Field_start@4,
0,
[],
Rows@2,
newline_found
);
{<<"\"\n"/utf8, Rest@3/binary>>, parsing_escaped_field} ->
Field@4 = extract_field(Original, Field_start, Field_length, Status),
Row@6 = lists:reverse([Field@4 | Row]),
Rows@2 = [Row@6 | Rows],
Field_start@4 = (Field_start + Field_length) + 2,
do_parse(
Rest@3,
Original,
Field_start@4,
0,
[],
Rows@2,
newline_found
);
{<<"\"\r\n"/utf8, Rest@4/binary>>, parsing_escaped_field} ->
Field@5 = extract_field(Original, Field_start, Field_length, Status),
Row@7 = lists:reverse([Field@5 | Row]),
Rows@3 = [Row@7 | Rows],
Field_start@5 = (Field_start + Field_length) + 3,
do_parse(
Rest@4,
Original,
Field_start@5,
0,
[],
Rows@3,
newline_found
);
{<<"\n"/utf8, Rest@5/binary>>, comma_found} ->
Row@8 = lists:reverse([<<""/utf8>> | Row]),
Rows@4 = [Row@8 | Rows],
do_parse(
Rest@5,
Original,
Field_start + 1,
0,
[],
Rows@4,
newline_found
);
{<<"\r\n"/utf8, Rest@6/binary>>, comma_found} ->
Row@9 = lists:reverse([<<""/utf8>> | Row]),
Rows@5 = [Row@9 | Rows],
do_parse(
Rest@6,
Original,
Field_start + 2,
0,
[],
Rows@5,
newline_found
);
{<<"\n"/utf8, Rest@7/binary>>, newline_found} ->
do_parse(Rest@7, Original, Field_start + 1, 0, Row, Rows, Status);
{<<"\r\n"/utf8, Rest@8/binary>>, newline_found} ->
do_parse(Rest@8, Original, Field_start + 2, 0, Row, Rows, Status);
{<<"\"\""/utf8, Rest@9/binary>>, parsing_escaped_field} ->
do_parse(
Rest@9,
Original,
Field_start,
Field_length + 2,
Row,
Rows,
Status
);
{<<"\""/utf8, _/binary>>, parsing_unescaped_field} ->
{error, {unescaped_quote, Field_start + Field_length}};
{<<"\""/utf8, _/binary>>, parsing_escaped_field} ->
{error, {unescaped_quote, Field_start + Field_length}};
{<<"\""/utf8, Rest@10/binary>>, comma_found} ->
Status@1 = parsing_escaped_field,
do_parse(Rest@10, Original, Field_start + 1, 0, Row, Rows, Status@1);
{<<"\""/utf8, Rest@10/binary>>, newline_found} ->
Status@1 = parsing_escaped_field,
do_parse(Rest@10, Original, Field_start + 1, 0, Row, Rows, Status@1);
{_, comma_found} ->
Status@2 = case Status of
parsing_escaped_field ->
parsing_escaped_field;
comma_found ->
parsing_unescaped_field;
newline_found ->
parsing_unescaped_field;
parsing_unescaped_field ->
parsing_unescaped_field
end,
Rest@11 = gsv_ffi:drop_bytes(String, 1),
do_parse(
Rest@11,
Original,
Field_start,
Field_length + 1,
Row,
Rows,
Status@2
);
{_, newline_found} ->
Status@2 = case Status of
parsing_escaped_field ->
parsing_escaped_field;
comma_found ->
parsing_unescaped_field;
newline_found ->
parsing_unescaped_field;
parsing_unescaped_field ->
parsing_unescaped_field
end,
Rest@11 = gsv_ffi:drop_bytes(String, 1),
do_parse(
Rest@11,
Original,
Field_start,
Field_length + 1,
Row,
Rows,
Status@2
);
{_, parsing_unescaped_field} ->
Status@2 = case Status of
parsing_escaped_field ->
parsing_escaped_field;
comma_found ->
parsing_unescaped_field;
newline_found ->
parsing_unescaped_field;
parsing_unescaped_field ->
parsing_unescaped_field
end,
Rest@11 = gsv_ffi:drop_bytes(String, 1),
do_parse(
Rest@11,
Original,
Field_start,
Field_length + 1,
Row,
Rows,
Status@2
);
{_, parsing_escaped_field} ->
Status@2 = case Status of
parsing_escaped_field ->
parsing_escaped_field;
comma_found ->
parsing_unescaped_field;
newline_found ->
parsing_unescaped_field;
parsing_unescaped_field ->
parsing_unescaped_field
end,
Rest@11 = gsv_ffi:drop_bytes(String, 1),
do_parse(
Rest@11,
Original,
Field_start,
Field_length + 1,
Row,
Rows,
Status@2
)
end.
-file("/Users/benjamin/Personal/gsv/src/gsv.gleam", 79).
-spec to_lists(binary()) -> {ok, list(list(binary()))} | {error, parse_error()}.
to_lists(Input) ->
case Input of
<<"\n"/utf8, Rest/binary>> ->
to_lists(Rest);
<<"\r\n"/utf8, Rest/binary>> ->
to_lists(Rest);
<<"\""/utf8, Rest@1/binary>> ->
do_parse(Rest@1, Input, 1, 0, [], [], parsing_escaped_field);
<<","/utf8, Rest@2/binary>> ->
do_parse(Rest@2, Input, 1, 0, [<<""/utf8>>], [], comma_found);
_ ->
do_parse(Input, Input, 0, 0, [], [], parsing_unescaped_field)
end.
-file("/Users/benjamin/Personal/gsv/src/gsv.gleam", 350).
-spec to_dicts(binary()) -> {ok, list(gleam@dict:dict(binary(), binary()))} |
{error, parse_error()}.
to_dicts(Input) ->
gleam@result:map(to_lists(Input), fun(Rows) -> case Rows of
[] ->
[];
[Headers | Rows@1] ->
Headers@1 = erlang:list_to_tuple(Headers),
gleam@list:map(
Rows@1,
fun(Row) ->
gleam@list:index_fold(
Row,
maps:new(),
fun(Row@1, Field, Index) -> case Field of
<<""/utf8>> ->
Row@1;
_ ->
case glearray:get(Headers@1, Index) of
{ok, Header} ->
gleam@dict:insert(
Row@1,
Header,
Field
);
{error, _} ->
Row@1
end
end end
)
end
)
end end).