Packages

Primitives for emitting and linting Datadog query syntax.

Current section

Files

Jump to
datadog_query src datadog_query@parse.erl
Raw

src/datadog_query@parse.erl

-module(datadog_query@parse).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/datadog_query/parse.gleam").
-export([filter/1]).
-export_type([parse_error/0, separator/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type parse_error() :: unexpected_end | {unexpected, binary()} | empty_input.
-type separator() :: sep_colon |
{sep_compare, datadog_query@ast:comparison_op()} |
sep_regex |
sep_in |
sep_not_in.
-file("src/datadog_query/parse.gleam", 359).
-spec skip_whitespace(list(binary())) -> list(binary()).
skip_whitespace(Chars) ->
case Chars of
[<<" "/utf8>> | Rest] ->
skip_whitespace(Rest);
[<<"\t"/utf8>> | Rest] ->
skip_whitespace(Rest);
[<<"\n"/utf8>> | Rest] ->
skip_whitespace(Rest);
[<<"\r"/utf8>> | Rest] ->
skip_whitespace(Rest);
_ ->
Chars
end.
-file("src/datadog_query/parse.gleam", 305).
-spec is_bare_value_char(binary()) -> boolean().
is_bare_value_char(C) ->
case C of
<<" "/utf8>> ->
false;
<<"\t"/utf8>> ->
false;
<<"\n"/utf8>> ->
false;
<<"\r"/utf8>> ->
false;
<<","/utf8>> ->
false;
<<"("/utf8>> ->
false;
<<")"/utf8>> ->
false;
<<"}"/utf8>> ->
false;
_ ->
true
end.
-file("src/datadog_query/parse.gleam", 411).
-spec do_take_while(
list(binary()),
fun((binary()) -> boolean()),
list(binary())
) -> {list(binary()), list(binary())}.
do_take_while(Chars, Pred, Acc) ->
case Chars of
[C | Rest] ->
case Pred(C) of
true ->
do_take_while(Rest, Pred, [C | Acc]);
false ->
{lists:reverse(Acc), Chars}
end;
[] ->
{lists:reverse(Acc), Chars}
end.
-file("src/datadog_query/parse.gleam", 404).
-spec take_while(list(binary()), fun((binary()) -> boolean())) -> {list(binary()),
list(binary())}.
take_while(Chars, Pred) ->
do_take_while(Chars, Pred, []).
-file("src/datadog_query/parse.gleam", 314).
-spec parse_quoted(list(binary()), list(binary())) -> {ok,
{binary(), list(binary())}} |
{error, parse_error()}.
parse_quoted(Chars, Acc) ->
case Chars of
[] ->
{error, unexpected_end};
[<<"\\"/utf8>>, <<"\""/utf8>> | Rest] ->
parse_quoted(Rest, [<<"\""/utf8>> | Acc]);
[<<"\\"/utf8>>, C | Rest@1] ->
parse_quoted(Rest@1, [C, <<"\\"/utf8>> | Acc]);
[<<"\""/utf8>> | Rest@2] ->
{ok, {erlang:list_to_binary(lists:reverse(Acc)), Rest@2}};
[C@1 | Rest@3] ->
parse_quoted(Rest@3, [C@1 | Acc])
end.
-file("src/datadog_query/parse.gleam", 288).
-spec parse_value(list(binary())) -> {ok, {binary(), list(binary())}} |
{error, parse_error()}.
parse_value(Chars) ->
case Chars of
[<<"\""/utf8>> | Rest] ->
parse_quoted(Rest, []);
_ ->
case take_while(Chars, fun is_bare_value_char/1) of
{[], _} ->
case Chars of
[] ->
{error, unexpected_end};
[C | _] ->
{error, {unexpected, C}}
end;
{Taken, Rest@1} ->
{ok, {erlang:list_to_binary(Taken), Rest@1}}
end
end.
-file("src/datadog_query/parse.gleam", 338).
-spec collect_values(list(binary()), list(binary())) -> {ok,
{list(binary()), list(binary())}} |
{error, parse_error()}.
collect_values(Acc, Chars) ->
case Chars of
[<<")"/utf8>> | Rest] ->
{ok, {lists:reverse(Acc), Rest}};
_ ->
gleam@result:'try'(
parse_value(Chars),
fun(_use0) ->
{Value, Rest@1} = _use0,
Rest@2 = skip_whitespace(Rest@1),
case Rest@2 of
[<<","/utf8>> | Tail] ->
collect_values([Value | Acc], skip_whitespace(Tail));
[<<")"/utf8>> | Tail@1] ->
{ok, {lists:reverse([Value | Acc]), Tail@1}};
[] ->
{error, unexpected_end};
[C | _] ->
{error, {unexpected, C}}
end
end
)
end.
-file("src/datadog_query/parse.gleam", 327).
-spec parse_value_list(list(binary())) -> {ok, {list(binary()), list(binary())}} |
{error, parse_error()}.
parse_value_list(Chars) ->
Chars@1 = skip_whitespace(Chars),
case Chars@1 of
[<<"("/utf8>> | Rest] ->
collect_values([], skip_whitespace(Rest));
[] ->
{error, unexpected_end};
[C | _] ->
{error, {unexpected, C}}
end.
-file("src/datadog_query/parse.gleam", 426).
-spec is_alnum(binary()) -> boolean().
is_alnum(C) ->
case C of
<<"0"/utf8>> ->
true;
<<"1"/utf8>> ->
true;
<<"2"/utf8>> ->
true;
<<"3"/utf8>> ->
true;
<<"4"/utf8>> ->
true;
<<"5"/utf8>> ->
true;
<<"6"/utf8>> ->
true;
<<"7"/utf8>> ->
true;
<<"8"/utf8>> ->
true;
<<"9"/utf8>> ->
true;
<<"a"/utf8>> ->
true;
<<"b"/utf8>> ->
true;
<<"c"/utf8>> ->
true;
<<"d"/utf8>> ->
true;
<<"e"/utf8>> ->
true;
<<"f"/utf8>> ->
true;
<<"g"/utf8>> ->
true;
<<"h"/utf8>> ->
true;
<<"i"/utf8>> ->
true;
<<"j"/utf8>> ->
true;
<<"k"/utf8>> ->
true;
<<"l"/utf8>> ->
true;
<<"m"/utf8>> ->
true;
<<"n"/utf8>> ->
true;
<<"o"/utf8>> ->
true;
<<"p"/utf8>> ->
true;
<<"q"/utf8>> ->
true;
<<"r"/utf8>> ->
true;
<<"s"/utf8>> ->
true;
<<"t"/utf8>> ->
true;
<<"u"/utf8>> ->
true;
<<"v"/utf8>> ->
true;
<<"w"/utf8>> ->
true;
<<"x"/utf8>> ->
true;
<<"y"/utf8>> ->
true;
<<"z"/utf8>> ->
true;
<<"A"/utf8>> ->
true;
<<"B"/utf8>> ->
true;
<<"C"/utf8>> ->
true;
<<"D"/utf8>> ->
true;
<<"E"/utf8>> ->
true;
<<"F"/utf8>> ->
true;
<<"G"/utf8>> ->
true;
<<"H"/utf8>> ->
true;
<<"I"/utf8>> ->
true;
<<"J"/utf8>> ->
true;
<<"K"/utf8>> ->
true;
<<"L"/utf8>> ->
true;
<<"M"/utf8>> ->
true;
<<"N"/utf8>> ->
true;
<<"O"/utf8>> ->
true;
<<"P"/utf8>> ->
true;
<<"Q"/utf8>> ->
true;
<<"R"/utf8>> ->
true;
<<"S"/utf8>> ->
true;
<<"T"/utf8>> ->
true;
<<"U"/utf8>> ->
true;
<<"V"/utf8>> ->
true;
<<"W"/utf8>> ->
true;
<<"X"/utf8>> ->
true;
<<"Y"/utf8>> ->
true;
<<"Z"/utf8>> ->
true;
_ ->
false
end.
-file("src/datadog_query/parse.gleam", 279).
-spec is_ident_char(binary()) -> boolean().
is_ident_char(C) ->
case C of
<<"."/utf8>> ->
true;
<<"_"/utf8>> ->
true;
<<"-"/utf8>> ->
true;
<<"@"/utf8>> ->
true;
_ ->
is_alnum(C)
end.
-file("src/datadog_query/parse.gleam", 389).
-spec strip_prefix(list(binary()), list(binary())) -> {ok, list(binary())} |
{error, nil}.
strip_prefix(Chars, Prefix) ->
case {Prefix, Chars} of
{[], _} ->
{ok, Chars};
{[_ | _], []} ->
{error, nil};
{[P | Ps], [C | Cs]} ->
case P =:= C of
true ->
strip_prefix(Cs, Ps);
false ->
{error, nil}
end
end.
-file("src/datadog_query/parse.gleam", 370).
?DOC(
" Consumes `keyword` from `chars` only if (a) it appears verbatim AND\n"
" (b) the character immediately after isn't an ident continuation\n"
" (so `OR` matches but `ORder` does not).\n"
).
-spec match_keyword(list(binary()), binary()) -> {ok, list(binary())} |
{error, nil}.
match_keyword(Chars, Keyword) ->
Kw_chars = gleam@string:to_graphemes(Keyword),
case strip_prefix(Chars, Kw_chars) of
{ok, Rest} ->
case Rest of
[] ->
{ok, Rest};
[C | _] ->
case is_ident_char(C) of
true ->
{error, nil};
false ->
{ok, Rest}
end
end;
{error, _} ->
{error, nil}
end.
-file("src/datadog_query/parse.gleam", 231).
?DOC(
" Looks for a separator immediately after the tag name (`tight`, no space)\n"
" or after intervening whitespace (`loose`, for `IN`/`NOT IN`).\n"
).
-spec parse_separator(list(binary()), list(binary())) -> {ok,
{separator(), list(binary())}} |
{error, parse_error()}.
parse_separator(Tight, Loose) ->
case Tight of
[<<":"/utf8>>, <<">"/utf8>>, <<"="/utf8>> | Rest] ->
{ok, {{sep_compare, gte}, Rest}};
[<<":"/utf8>>, <<"<"/utf8>>, <<"="/utf8>> | Rest@1] ->
{ok, {{sep_compare, lte}, Rest@1}};
[<<":"/utf8>>, <<">"/utf8>> | Rest@2] ->
{ok, {{sep_compare, gt}, Rest@2}};
[<<":"/utf8>>, <<"<"/utf8>> | Rest@3] ->
{ok, {{sep_compare, lt}, Rest@3}};
[<<":"/utf8>>, <<"~"/utf8>> | Rest@4] ->
{ok, {sep_regex, Rest@4}};
[<<":"/utf8>> | Rest@5] ->
{ok, {sep_colon, Rest@5}};
_ ->
case match_keyword(Loose, <<"NOT"/utf8>>) of
{ok, After_not} ->
After_not_ws = skip_whitespace(After_not),
case match_keyword(After_not_ws, <<"IN"/utf8>>) of
{ok, Rest@6} ->
{ok, {sep_not_in, skip_whitespace(Rest@6)}};
{error, _} ->
{error,
{unexpected,
<<"NOT without IN after tag name"/utf8>>}}
end;
{error, _} ->
case match_keyword(Loose, <<"IN"/utf8>>) of
{ok, Rest@7} ->
{ok, {sep_in, skip_whitespace(Rest@7)}};
{error, _} ->
case Loose of
[] ->
{error, unexpected_end};
[C | _] ->
{error, {unexpected, C}}
end
end
end
end.
-file("src/datadog_query/parse.gleam", 266).
-spec parse_ident(list(binary())) -> {ok, {binary(), list(binary())}} |
{error, parse_error()}.
parse_ident(Chars) ->
case take_while(Chars, fun is_ident_char/1) of
{[], _} ->
case Chars of
[] ->
{error, unexpected_end};
[C | _] ->
{error, {unexpected, C}}
end;
{Taken, Rest} ->
{ok, {erlang:list_to_binary(Taken), Rest}}
end.
-file("src/datadog_query/parse.gleam", 166).
-spec parse_simple_filter(list(binary())) -> {ok,
{datadog_query@ast:filter(), list(binary())}} |
{error, parse_error()}.
parse_simple_filter(Chars) ->
{Negated, Chars@1} = case Chars of
[<<"!"/utf8>> | Rest] ->
{true, Rest};
_ ->
{false, Chars}
end,
gleam@result:'try'(
parse_ident(Chars@1),
fun(_use0) ->
{Name, Rest@1} = _use0,
Rest_ws = skip_whitespace(Rest@1),
case parse_separator(Rest@1, Rest_ws) of
{ok, {sep_colon, After}} ->
gleam@result:'try'(
parse_value(After),
fun(_use0@1) ->
{Value, After@1} = _use0@1,
case Negated of
true ->
{ok, {{negated_tag, Name, Value}, After@1}};
false ->
{ok, {{tag, Name, Value}, After@1}}
end
end
);
{ok, {{sep_compare, Op}, After@2}} ->
gleam@result:'try'(
parse_value(After@2),
fun(_use0@2) ->
{Value@1, After@3} = _use0@2,
Node = {tag_comparison, Name, Op, Value@1},
case Negated of
true ->
{ok, {{'not', Node}, After@3}};
false ->
{ok, {Node, After@3}}
end
end
);
{ok, {sep_regex, After@4}} ->
gleam@result:'try'(
parse_value(After@4),
fun(_use0@3) ->
{Value@2, After@5} = _use0@3,
Node@1 = {tag_regex, Name, Value@2},
case Negated of
true ->
{ok, {{'not', Node@1}, After@5}};
false ->
{ok, {Node@1, After@5}}
end
end
);
{ok, {sep_in, After@6}} ->
gleam@result:'try'(
parse_value_list(After@6),
fun(_use0@4) ->
{Values, After@7} = _use0@4,
Node@2 = {tag_in, Name, Values},
case Negated of
true ->
{ok, {{'not', Node@2}, After@7}};
false ->
{ok, {Node@2, After@7}}
end
end
);
{ok, {sep_not_in, After@8}} ->
gleam@result:'try'(
parse_value_list(After@8),
fun(_use0@5) ->
{Values@1, After@9} = _use0@5,
Node@3 = {tag_not_in, Name, Values@1},
case Negated of
true ->
{ok, {{'not', Node@3}, After@9}};
false ->
{ok, {Node@3, After@9}}
end
end
);
{error, E} ->
{error, E}
end
end
).
-file("src/datadog_query/parse.gleam", 150).
-spec is_filter_terminator(list(binary())) -> boolean().
is_filter_terminator(Chars) ->
case Chars of
[] ->
true;
[<<")"/utf8>> | _] ->
true;
_ ->
case match_keyword(Chars, <<"AND"/utf8>>) of
{ok, _} ->
true;
{error, _} ->
case match_keyword(Chars, <<"OR"/utf8>>) of
{ok, _} ->
true;
{error, _} ->
false
end
end
end.
-file("src/datadog_query/parse.gleam", 135).
-spec parse_simple_or_wildcard(list(binary())) -> {ok,
{datadog_query@ast:filter(), list(binary())}} |
{error, parse_error()}.
parse_simple_or_wildcard(Chars) ->
case Chars of
[<<"*"/utf8>> | Rest] ->
case is_filter_terminator(skip_whitespace(Rest)) of
true ->
{ok, {wildcard, Rest}};
false ->
parse_simple_filter(Chars)
end;
_ ->
parse_simple_filter(Chars)
end.
-file("src/datadog_query/parse.gleam", 118).
-spec parse_atom(list(binary())) -> {ok,
{datadog_query@ast:filter(), list(binary())}} |
{error, parse_error()}.
parse_atom(Chars) ->
case Chars of
[<<"("/utf8>> | Rest] ->
gleam@result:'try'(
parse_or(skip_whitespace(Rest)),
fun(_use0) ->
{Inner, Rest@1} = _use0,
Rest@2 = skip_whitespace(Rest@1),
case Rest@2 of
[<<")"/utf8>> | Tail] ->
{ok, {Inner, Tail}};
[] ->
{error, unexpected_end};
[C | _] ->
{error, {unexpected, C}}
end
end
);
_ ->
parse_simple_or_wildcard(Chars)
end.
-file("src/datadog_query/parse.gleam", 95).
-spec parse_primary(list(binary())) -> {ok,
{datadog_query@ast:filter(), list(binary())}} |
{error, parse_error()}.
parse_primary(Chars) ->
Chars@1 = skip_whitespace(Chars),
case match_keyword(Chars@1, <<"NOT"/utf8>>) of
{ok, Rest} ->
After_ws = skip_whitespace(Rest),
case match_keyword(After_ws, <<"IN"/utf8>>) of
{ok, _} ->
parse_atom(Chars@1);
{error, _} ->
gleam@result:'try'(
parse_primary(After_ws),
fun(_use0) ->
{Inner, Rest@1} = _use0,
{ok, {{'not', Inner}, Rest@1}}
end
)
end;
{error, _} ->
parse_atom(Chars@1)
end.
-file("src/datadog_query/parse.gleam", 77).
-spec collect_and(list(datadog_query@ast:filter()), list(binary())) -> {ok,
{datadog_query@ast:filter(), list(binary())}} |
{error, parse_error()}.
collect_and(Acc, Chars) ->
Chars@1 = skip_whitespace(Chars),
case match_keyword(Chars@1, <<"AND"/utf8>>) of
{ok, Rest} ->
gleam@result:'try'(
parse_primary(skip_whitespace(Rest)),
fun(_use0) ->
{Next, Rest@1} = _use0,
collect_and([Next | Acc], Rest@1)
end
);
{error, _} ->
case Acc of
[Single] ->
{ok, {Single, Chars@1}};
Many ->
{ok, {{'and', lists:reverse(Many)}, Chars@1}}
end
end.
-file("src/datadog_query/parse.gleam", 72).
-spec parse_and(list(binary())) -> {ok,
{datadog_query@ast:filter(), list(binary())}} |
{error, parse_error()}.
parse_and(Chars) ->
gleam@result:'try'(
parse_primary(Chars),
fun(_use0) ->
{First, Rest} = _use0,
collect_and([First], Rest)
end
).
-file("src/datadog_query/parse.gleam", 54).
-spec collect_or(list(datadog_query@ast:filter()), list(binary())) -> {ok,
{datadog_query@ast:filter(), list(binary())}} |
{error, parse_error()}.
collect_or(Acc, Chars) ->
Chars@1 = skip_whitespace(Chars),
case match_keyword(Chars@1, <<"OR"/utf8>>) of
{ok, Rest} ->
gleam@result:'try'(
parse_and(skip_whitespace(Rest)),
fun(_use0) ->
{Next, Rest@1} = _use0,
collect_or([Next | Acc], Rest@1)
end
);
{error, _} ->
case Acc of
[Single] ->
{ok, {Single, Chars@1}};
Many ->
{ok, {{'or', lists:reverse(Many)}, Chars@1}}
end
end.
-file("src/datadog_query/parse.gleam", 49).
-spec parse_or(list(binary())) -> {ok,
{datadog_query@ast:filter(), list(binary())}} |
{error, parse_error()}.
parse_or(Chars) ->
gleam@result:'try'(
parse_and(Chars),
fun(_use0) ->
{First, Rest} = _use0,
collect_or([First], Rest)
end
).
-file("src/datadog_query/parse.gleam", 32).
-spec filter(binary()) -> {ok, datadog_query@ast:filter()} |
{error, parse_error()}.
filter(Input) ->
Chars = gleam@string:to_graphemes(Input),
Chars@1 = skip_whitespace(Chars),
case Chars@1 of
[] ->
{error, empty_input};
_ ->
gleam@result:'try'(
parse_or(Chars@1),
fun(_use0) ->
{Parsed, Rest} = _use0,
case skip_whitespace(Rest) of
[] ->
{ok, Parsed};
Leftover ->
{error,
{unexpected, erlang:list_to_binary(Leftover)}}
end
end
)
end.