Packages
caffeine_lang
6.3.0
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_query_language@parser.erl
-module(caffeine_query_language@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_query_language/parser.gleam").
-export([find_rightmost_operator_at_level/5, is_balanced_parens/3, parse_expr/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/caffeine_query_language/parser.gleam", 401).
-spec count_parens(integer(), binary(), integer()) -> integer().
count_parens(Cur_count, Input, Pos) ->
case parser_ffi:code_unit_at(Input, Pos) of
C when C =:= 16#28 ->
Cur_count + 1;
C@1 when C@1 =:= 16#29 ->
Cur_count - 1;
_ ->
Cur_count
end.
-file("src/caffeine_query_language/parser.gleam", 357).
?DOC(" Internal loop with pre-computed lengths.\n").
-spec find_rightmost_operator_at_level_loop(
binary(),
binary(),
integer(),
integer(),
integer(),
integer(),
integer()
) -> {ok, {binary(), binary()}} |
{error, caffeine_lang@errors:compilation_error()}.
find_rightmost_operator_at_level_loop(
Input,
Operator,
Start_pos,
Paren_level,
Rightmost_pos,
Operator_length,
Input_len
) ->
case Start_pos >= Input_len of
true ->
case Rightmost_pos of
-1 ->
{error,
caffeine_lang@errors:cql_parser_error(
<<"Operator not found"/utf8>>
)};
Pos ->
Left = gleam@string:trim(
parser_ffi:slice_codeunits(Input, 0, Pos)
),
Right_start = Pos + Operator_length,
Right_length = Input_len - Right_start,
Right = gleam@string:trim(
parser_ffi:slice_codeunits(
Input,
Right_start,
Right_length
)
),
{ok, {Left, Right}}
end;
false ->
New_paren_level = count_parens(Paren_level, Input, Start_pos),
New_rightmost_pos = case (New_paren_level =:= 0) andalso parser_ffi:substring_equals_at(
Input,
Start_pos,
Operator
) of
true ->
Start_pos;
false ->
Rightmost_pos
end,
find_rightmost_operator_at_level_loop(
Input,
Operator,
Start_pos + 1,
New_paren_level,
New_rightmost_pos,
Operator_length,
Input_len
)
end.
-file("src/caffeine_query_language/parser.gleam", 338).
?DOC(false).
-spec find_rightmost_operator_at_level(
binary(),
binary(),
integer(),
integer(),
integer()
) -> {ok, {binary(), binary()}} |
{error, caffeine_lang@errors:compilation_error()}.
find_rightmost_operator_at_level(
Input,
Operator,
Start_pos,
Paren_level,
Rightmost_pos
) ->
find_rightmost_operator_at_level_loop(
Input,
Operator,
Start_pos,
Paren_level,
Rightmost_pos,
parser_ffi:code_unit_length(Operator),
parser_ffi:code_unit_length(Input)
).
-file("src/caffeine_query_language/parser.gleam", 306).
-spec find_operator(binary(), binary()) -> {ok, {binary(), binary()}} |
{error, caffeine_lang@errors:compilation_error()}.
find_operator(Input, Operator) ->
find_rightmost_operator_at_level(Input, Operator, 0, 0, -1).
-file("src/caffeine_query_language/parser.gleam", 251).
?DOC(" Parses an integer string as a float.\n").
-spec parse_int_as_float(binary()) -> {ok, float()} | {error, binary()}.
parse_int_as_float(Input) ->
gleam@bool:guard(
gleam_stdlib:contains_string(Input, <<"."/utf8>>),
{error, <<"Not an integer"/utf8>>},
fun() -> _pipe = gleam_stdlib:parse_float(<<Input/binary, ".0"/utf8>>),
gleam@result:map_error(
_pipe,
fun(_) -> <<"Invalid number"/utf8>> end
) end
).
-file("src/caffeine_query_language/parser.gleam", 261).
?DOC(" Parses an interval like \"10s\", \"5m\", \"1h\", \"500ms\", \"1d\" into seconds.\n").
-spec parse_interval(binary()) -> {ok, float()} | {error, binary()}.
parse_interval(Input) ->
Trimmed = gleam@string:trim(Input),
case Trimmed of
<<""/utf8>> ->
{error, <<"Missing interval in time_slice expression"/utf8>>};
_ ->
Len = string:length(Trimmed),
{Unit, Number_part} = case (Len >= 3) andalso (gleam@string:slice(
Trimmed,
Len - 2,
2
)
=:= <<"ms"/utf8>>) of
true ->
{<<"ms"/utf8>>, gleam@string:slice(Trimmed, 0, Len - 2)};
false ->
{gleam@string:slice(Trimmed, Len - 1, 1),
gleam@string:slice(Trimmed, 0, Len - 1)}
end,
gleam@result:'try'(case Unit of
<<"ms"/utf8>> ->
{ok, 0.001};
<<"s"/utf8>> ->
{ok, 1.0};
<<"m"/utf8>> ->
{ok, 60.0};
<<"h"/utf8>> ->
{ok, 3600.0};
<<"d"/utf8>> ->
{ok, 86400.0};
_ ->
{error,
<<<<"Invalid interval unit '"/utf8, Unit/binary>>/binary,
"' (expected ms, s, m, h, or d)"/utf8>>}
end, fun(Multiplier) ->
gleam@result:'try'(
case gleam_stdlib:parse_float(Number_part) of
{ok, F} ->
{ok, F};
{error, _} ->
case parse_int_as_float(Number_part) of
{ok, F@1} ->
{ok, F@1};
{error, _} ->
{error,
<<<<"Invalid interval number '"/utf8,
Number_part/binary>>/binary,
"'"/utf8>>}
end
end,
fun(Number) -> {ok, Number * Multiplier} end
)
end)
end.
-file("src/caffeine_query_language/parser.gleam", 231).
?DOC(" Parses a threshold value as a float.\n").
-spec parse_threshold(binary()) -> {ok, float()} | {error, binary()}.
parse_threshold(Input) ->
Trimmed = gleam@string:trim(Input),
case Trimmed of
<<""/utf8>> ->
{error, <<"Missing threshold in time_slice expression"/utf8>>};
_ ->
case gleam_stdlib:parse_float(Trimmed) of
{ok, F} ->
{ok, F};
{error, _} ->
case parse_int_as_float(Trimmed) of
{ok, F@1} ->
{ok, F@1};
{error, _} ->
{error,
<<<<"Invalid threshold '"/utf8, Trimmed/binary>>/binary,
"' in time_slice expression"/utf8>>}
end
end
end.
-file("src/caffeine_query_language/parser.gleam", 194).
-spec find_substring_position_loop(
binary(),
binary(),
integer(),
integer(),
integer()
) -> gleam@option:option(integer()).
find_substring_position_loop(Haystack, Needle, Pos, Needle_len, Haystack_len) ->
gleam@bool:guard(
(Pos + Needle_len) > Haystack_len,
none,
fun() ->
gleam@bool:guard(
parser_ffi:substring_equals_at(Haystack, Pos, Needle),
{some, Pos},
fun() ->
find_substring_position_loop(
Haystack,
Needle,
Pos + 1,
Needle_len,
Haystack_len
)
end
)
end
).
-file("src/caffeine_query_language/parser.gleam", 184).
?DOC(" Finds the position of a substring in a string. Returns a codeunit position.\n").
-spec find_substring_position(binary(), binary()) -> gleam@option:option(integer()).
find_substring_position(Haystack, Needle) ->
find_substring_position_loop(
Haystack,
Needle,
0,
parser_ffi:code_unit_length(Needle),
parser_ffi:code_unit_length(Haystack)
).
-file("src/caffeine_query_language/parser.gleam", 216).
?DOC(" Splits on \"per\" keyword, returning (threshold_str, interval_str).\n").
-spec split_on_per(binary()) -> {ok, {binary(), binary()}} | {error, binary()}.
split_on_per(Input) ->
case find_substring_position(Input, <<"per"/utf8>>) of
{some, Pos} ->
Threshold_str = gleam@string:trim(
parser_ffi:slice_codeunits(Input, 0, Pos)
),
Rest_start = Pos + 3,
Rest_len = parser_ffi:code_unit_length(Input) - Rest_start,
Interval_str = gleam@string:trim(
parser_ffi:slice_codeunits(Input, Rest_start, Rest_len)
),
{ok, {Threshold_str, Interval_str}};
none ->
{error, <<"Missing 'per' keyword in time_slice expression"/utf8>>}
end.
-file("src/caffeine_query_language/parser.gleam", 162).
-spec find_comparator_loop(
binary(),
list({binary(), caffeine_query_language@ast:comparator()})
) -> {ok, {binary(), caffeine_query_language@ast:comparator(), binary()}} |
{error, binary()}.
find_comparator_loop(Input, Comparators) ->
case Comparators of
[] ->
{error, <<"No comparator found in time_slice expression"/utf8>>};
[{Comp_str, Comp} | Rest] ->
case find_substring_position(Input, Comp_str) of
{some, Pos} ->
Query = parser_ffi:slice_codeunits(Input, 0, Pos),
Rest_start = Pos + parser_ffi:code_unit_length(Comp_str),
Rest_len = parser_ffi:code_unit_length(Input) - Rest_start,
Rest_str = parser_ffi:slice_codeunits(
Input,
Rest_start,
Rest_len
),
{ok, {Query, Comp, Rest_str}};
none ->
find_comparator_loop(Input, Rest)
end
end.
-file("src/caffeine_query_language/parser.gleam", 149).
?DOC(" Finds a comparator in the input and splits into (query, comparator, rest).\n").
-spec find_comparator(binary()) -> {ok,
{binary(), caffeine_query_language@ast:comparator(), binary()}} |
{error, binary()}.
find_comparator(Input) ->
Comparators = [{<<">="/utf8>>, greater_than_or_equal_to},
{<<"<="/utf8>>, less_than_or_equal_to},
{<<">"/utf8>>, greater_than},
{<<"<"/utf8>>, less_than}],
find_comparator_loop(Input, Comparators).
-file("src/caffeine_query_language/parser.gleam", 120).
?DOC(
" Parses the inner content of a time_slice expression.\n"
" Format: \"<query> <comparator> <threshold> per <interval>\"\n"
" Example: \"avg:system.cpu > 80 per 300s\"\n"
).
-spec parse_time_slice_spec(binary()) -> {ok,
caffeine_query_language@ast:time_slice_exp()} |
{error, binary()}.
parse_time_slice_spec(Input) ->
Trimmed = gleam@string:trim(Input),
case Trimmed of
<<""/utf8>> ->
{error, <<"Empty time_slice expression"/utf8>>};
_ ->
gleam@result:'try'(
find_comparator(Trimmed),
fun(_use0) ->
{Query, Comparator, Rest} = _use0,
Query_trimmed = gleam@string:trim(Query),
case Query_trimmed of
<<""/utf8>> ->
{error,
<<"Missing query in time_slice expression"/utf8>>};
_ ->
gleam@result:'try'(
split_on_per(Rest),
fun(_use0@1) ->
{Threshold_str, Interval_str} = _use0@1,
gleam@result:'try'(
parse_threshold(Threshold_str),
fun(Threshold) ->
gleam@result:'try'(
parse_interval(Interval_str),
fun(Interval_seconds) ->
{ok,
{time_slice_exp,
Query_trimmed,
Comparator,
Threshold,
Interval_seconds}}
end
)
end
)
end
)
end
end
)
end.
-file("src/caffeine_query_language/parser.gleam", 103).
?DOC(
" Attempts to parse a keyword expression like \"time_slice(...)\".\n"
" Returns Error if the input is not a keyword expression.\n"
).
-spec try_parse_keyword_expr(binary()) -> {ok,
caffeine_query_language@ast:exp(caffeine_query_language@ast:cql_parsed())} |
{error, binary()}.
try_parse_keyword_expr(Input) ->
gleam@bool:guard(
not (gleam_stdlib:string_starts_with(Input, <<"time_slice("/utf8>>)
andalso gleam_stdlib:string_ends_with(Input, <<")"/utf8>>)),
{error, <<"Not a keyword expression"/utf8>>},
fun() ->
Prefix_len = string:length(<<"time_slice("/utf8>>),
Inner_len = (string:length(Input) - Prefix_len) - 1,
Inner = gleam@string:slice(Input, Prefix_len, Inner_len),
gleam@result:'try'(
parse_time_slice_spec(Inner),
fun(Spec) -> {ok, {time_slice_expr, Spec}} end
)
end
).
-file("src/caffeine_query_language/parser.gleam", 321).
?DOC(" Internal loop with pre-computed input length.\n").
-spec is_balanced_parens_loop(binary(), integer(), integer(), integer()) -> boolean().
is_balanced_parens_loop(Input, Pos, Count, Input_len) ->
gleam@bool:guard(
Pos >= Input_len,
Count =:= 0,
fun() ->
New_count = count_parens(Count, Input, Pos),
Does_not_close_too_early = not ((New_count =:= 0) andalso (Pos /= (Input_len
- 1))),
Does_not_close_too_early andalso is_balanced_parens_loop(
Input,
Pos + 1,
New_count,
Input_len
)
end
).
-file("src/caffeine_query_language/parser.gleam", 316).
?DOC(false).
-spec is_balanced_parens(binary(), integer(), integer()) -> boolean().
is_balanced_parens(Input, Pos, Count) ->
is_balanced_parens_loop(
Input,
Pos,
Count,
parser_ffi:code_unit_length(Input)
).
-file("src/caffeine_query_language/parser.gleam", 63).
-spec is_fully_parenthesized(binary()) -> boolean().
is_fully_parenthesized(Input) ->
(gleam_stdlib:string_starts_with(Input, <<"("/utf8>>) andalso gleam_stdlib:string_ends_with(
Input,
<<")"/utf8>>
))
andalso ((string:length(Input) >= 2) andalso is_balanced_parens(Input, 1, 1)).
-file("src/caffeine_query_language/parser.gleam", 69).
-spec try_operators(
binary(),
list({binary(), caffeine_query_language@ast:operator()})
) -> {ok,
caffeine_query_language@ast:exp(caffeine_query_language@ast:cql_parsed())} |
{error, binary()}.
try_operators(Input, Operators) ->
case Operators of
[] ->
case try_parse_keyword_expr(Input) of
{ok, Exp} ->
{ok, Exp};
{error, Err} ->
gleam@bool:guard(
gleam_stdlib:string_starts_with(
Input,
<<"time_slice("/utf8>>
)
andalso gleam_stdlib:string_ends_with(
Input,
<<")"/utf8>>
),
{error, Err},
fun() ->
Word = {word, Input},
{ok, {primary, {primary_word, Word}}}
end
)
end;
[{Op_str, Op} | Rest] ->
case find_operator(Input, Op_str) of
{ok, {Left, Right}} ->
gleam@result:'try'(
parse_expr(Left),
fun(Left_exp) ->
gleam@result:'try'(
parse_expr(Right),
fun(Right_exp) ->
{ok,
{operator_expr, Left_exp, Right_exp, Op}}
end
)
end
);
{error, _} ->
try_operators(Input, Rest)
end
end.
-file("src/caffeine_query_language/parser.gleam", 47).
?DOC(false).
-spec parse_expr(binary()) -> {ok,
caffeine_query_language@ast:exp(caffeine_query_language@ast:cql_parsed())} |
{error, binary()}.
parse_expr(Input) ->
Trimmed = gleam@string:trim(Input),
case is_fully_parenthesized(Trimmed) of
true ->
Inner = gleam@string:slice(Trimmed, 1, string:length(Trimmed) - 2),
gleam@result:'try'(
parse_expr(Inner),
fun(Inner_exp) -> {ok, {primary, {primary_exp, Inner_exp}}} end
);
false ->
Operators = [{<<"+"/utf8>>, add},
{<<"-"/utf8>>, sub},
{<<"*"/utf8>>, mul},
{<<"/"/utf8>>, 'div'}],
try_operators(Trimmed, Operators)
end.