-module(ghtml@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/ghtml/parser.gleam").
-export([tokenize/1, parse/1, format_error/2, format_errors/2]).
-export_type([stack_frame/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.
?MODULEDOC(
" Template parser for `.ghtml` files.\n"
"\n"
" Converts template source text into tokens and builds an AST representing\n"
" the template structure including HTML elements, expressions, and control flow.\n"
).
-type stack_frame() :: {element_frame,
binary(),
list(ghtml@types:attr()),
list(ghtml@types:node_()),
ghtml@types:span()} |
{if_frame,
binary(),
list(ghtml@types:node_()),
list(ghtml@types:node_()),
boolean(),
ghtml@types:span()} |
{each_frame,
binary(),
binary(),
gleam@option:option(binary()),
list(ghtml@types:node_()),
ghtml@types:span()} |
{case_frame,
binary(),
gleam@option:option(binary()),
list(ghtml@types:node_()),
list(ghtml@types:case_branch()),
ghtml@types:span()}.
-file("src/ghtml/parser.gleam", 154).
-spec advance_pos(ghtml@types:position(), binary()) -> ghtml@types:position().
advance_pos(Pos, Char) ->
case Char of
<<"\n"/utf8>> ->
{position, erlang:element(2, Pos) + 1, 1};
_ ->
{position, erlang:element(2, Pos), erlang:element(3, Pos) + 1}
end.
-file("src/ghtml/parser.gleam", 161).
-spec advance_pos_str(ghtml@types:position(), binary()) -> ghtml@types:position().
advance_pos_str(Pos, Str) ->
_pipe = gleam@string:to_graphemes(Str),
gleam@list:fold(_pipe, Pos, fun advance_pos/2).
-file("src/ghtml/parser.gleam", 232).
-spec split_params(binary(), list(binary()), binary(), integer()) -> list(binary()).
split_params(Input, Acc, Current, Depth) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
case Current of
<<""/utf8>> ->
lists:reverse(Acc);
_ ->
lists:reverse([Current | Acc])
end;
{ok, {Char, Rest}} ->
case Char of
<<"("/utf8>> ->
split_params(
Rest,
Acc,
<>,
Depth + 1
);
<<"["/utf8>> ->
split_params(
Rest,
Acc,
<>,
Depth + 1
);
<<"{"/utf8>> ->
split_params(
Rest,
Acc,
<>,
Depth + 1
);
<<")"/utf8>> ->
split_params(
Rest,
Acc,
<>,
Depth - 1
);
<<"]"/utf8>> ->
split_params(
Rest,
Acc,
<>,
Depth - 1
);
<<"}"/utf8>> ->
split_params(
Rest,
Acc,
<>,
Depth - 1
);
<<","/utf8>> when Depth =:= 0 ->
split_params(Rest, [Current | Acc], <<""/utf8>>, 0);
_ ->
split_params(
Rest,
Acc,
<>,
Depth
)
end
end.
-file("src/ghtml/parser.gleam", 213).
-spec parse_param_list(binary()) -> list({binary(), binary()}).
parse_param_list(Content) ->
_pipe = Content,
_pipe@1 = gleam@string:trim(_pipe),
_pipe@2 = split_params(_pipe@1, [], <<""/utf8>>, 0),
gleam@list:filter_map(
_pipe@2,
fun(Param_str) ->
Param_str@1 = gleam@string:trim(Param_str),
case Param_str@1 of
<<""/utf8>> ->
{error, nil};
_ ->
case gleam@string:split_once(Param_str@1, <<":"/utf8>>) of
{ok, {Name, Type_str}} ->
{ok,
{gleam@string:trim(Name),
gleam@string:trim(Type_str)}};
{error, _} ->
{error, nil}
end
end
end
).
-file("src/ghtml/parser.gleam", 358).
-spec is_tag_name_char(binary()) -> boolean().
is_tag_name_char(Char) ->
case Char of
<<"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;
<<"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;
<<"-"/utf8>> ->
true;
<<"_"/utf8>> ->
true;
_ ->
false
end.
-file("src/ghtml/parser.gleam", 342).
-spec extract_tag_name(binary(), binary(), ghtml@types:position()) -> {binary(),
binary(),
ghtml@types:position()}.
extract_tag_name(Input, Acc, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
{Acc, Input, Pos};
{ok, {Char, Rest}} ->
case is_tag_name_char(Char) of
true ->
extract_tag_name(
Rest,
<>,
advance_pos(Pos, Char)
);
false ->
{Acc, Input, Pos}
end
end.
-file("src/ghtml/parser.gleam", 559).
-spec is_attr_name_char(binary()) -> boolean().
is_attr_name_char(Char) ->
case Char of
<<"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;
<<"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;
<<"-"/utf8>> ->
true;
<<"_"/utf8>> ->
true;
<<":"/utf8>> ->
true;
_ ->
false
end.
-file("src/ghtml/parser.gleam", 543).
-spec extract_attr_name(binary(), binary(), ghtml@types:position()) -> {binary(),
binary(),
ghtml@types:position()}.
extract_attr_name(Input, Acc, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
{Acc, Input, Pos};
{ok, {Char, Rest}} ->
case is_attr_name_char(Char) of
true ->
extract_attr_name(
Rest,
<>,
advance_pos(Pos, Char)
);
false ->
{Acc, Input, Pos}
end
end.
-file("src/ghtml/parser.gleam", 630).
-spec extract_quoted_value(binary(), binary(), ghtml@types:position()) -> {ok,
{binary(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
extract_quoted_value(Input, Acc, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
{error,
{parse_error, {span, Pos, Pos}, <<"Unterminated string"/utf8>>}};
{ok, {<<"\""/utf8>>, Rest}} ->
End_pos = advance_pos(Pos, <<"\""/utf8>>),
{ok, {Acc, Rest, End_pos}};
{ok, {<<"\\"/utf8>>, Rest@1}} ->
case gleam_stdlib:string_pop_grapheme(Rest@1) of
{ok, {Escaped, Rest2}} ->
New_pos = advance_pos(
advance_pos(Pos, <<"\\"/utf8>>),
Escaped
),
extract_quoted_value(
Rest2,
<>,
New_pos
);
{error, _} ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Unterminated escape"/utf8>>}}
end;
{ok, {Char, Rest@2}} ->
extract_quoted_value(
Rest@2,
<>,
advance_pos(Pos, Char)
)
end.
-file("src/ghtml/parser.gleam", 657).
-spec extract_single_quoted_value(binary(), binary(), ghtml@types:position()) -> {ok,
{binary(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
extract_single_quoted_value(Input, Acc, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
{error,
{parse_error, {span, Pos, Pos}, <<"Unterminated string"/utf8>>}};
{ok, {<<"'"/utf8>>, Rest}} ->
End_pos = advance_pos(Pos, <<"'"/utf8>>),
{ok, {Acc, Rest, End_pos}};
{ok, {<<"\\"/utf8>>, Rest@1}} ->
case gleam_stdlib:string_pop_grapheme(Rest@1) of
{ok, {Escaped, Rest2}} ->
New_pos = advance_pos(
advance_pos(Pos, <<"\\"/utf8>>),
Escaped
),
extract_single_quoted_value(
Rest2,
<>,
New_pos
);
{error, _} ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Unterminated escape"/utf8>>}}
end;
{ok, {Char, Rest@2}} ->
extract_single_quoted_value(
Rest@2,
<>,
advance_pos(Pos, Char)
)
end.
-file("src/ghtml/parser.gleam", 815).
-spec find_as_keyword(binary(), binary(), ghtml@types:position()) -> {ok,
{binary(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
find_as_keyword(Input, Acc, Pos) ->
case Input of
<<""/utf8>> ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Expected 'as' keyword in each"/utf8>>}};
<<" as "/utf8, Rest/binary>> ->
New_pos = advance_pos_str(Pos, <<" as "/utf8>>),
{ok, {Acc, Rest, New_pos}};
_ ->
case gleam_stdlib:string_pop_grapheme(Input) of
{ok, {Char, Rest@1}} ->
find_as_keyword(
Rest@1,
<>,
advance_pos(Pos, Char)
);
{error, _} ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Expected 'as' keyword in each"/utf8>>}}
end
end.
-file("src/ghtml/parser.gleam", 844).
-spec extract_until_close_brace(binary(), binary(), ghtml@types:position()) -> {binary(),
binary(),
ghtml@types:position()}.
extract_until_close_brace(Input, Acc, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
{Acc, Input, Pos};
{ok, {<<"}"/utf8>>, Rest}} ->
End_pos = advance_pos(Pos, <<"}"/utf8>>),
{Acc, Rest, End_pos};
{ok, {Char, Rest@1}} ->
extract_until_close_brace(
Rest@1,
<>,
advance_pos(Pos, Char)
)
end.
-file("src/ghtml/parser.gleam", 860).
-spec parse_binding(binary()) -> {binary(), gleam@option:option(binary())}.
parse_binding(Binding) ->
Binding@1 = gleam@string:trim(Binding),
case gleam@string:split_once(Binding@1, <<","/utf8>>) of
{ok, {Item, Index}} ->
{gleam@string:trim(Item), {some, gleam@string:trim(Index)}};
{error, _} ->
{Binding@1, none}
end.
-file("src/ghtml/parser.gleam", 798).
-spec parse_each_header(binary(), ghtml@types:position()) -> {ok,
{binary(),
binary(),
gleam@option:option(binary()),
binary(),
ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
parse_each_header(Input, Pos) ->
case find_as_keyword(Input, <<""/utf8>>, Pos) of
{ok, {Collection, Rest, New_pos}} ->
{Binding, Rest@1, End_pos} = extract_until_close_brace(
Rest,
<<""/utf8>>,
New_pos
),
{Item, Index} = parse_binding(Binding),
{ok, {gleam@string:trim(Collection), Item, Index, Rest@1, End_pos}};
{error, Err} ->
{error, Err}
end.
-file("src/ghtml/parser.gleam", 947).
-spec extract_string_literal(binary(), binary(), ghtml@types:position()) -> {ok,
{binary(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
extract_string_literal(Input, Acc, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Unterminated string literal"/utf8>>}};
{ok, {<<"\\"/utf8>>, Rest}} ->
case gleam_stdlib:string_pop_grapheme(Rest) of
{ok, {Escaped, Rest2}} ->
New_pos = advance_pos(
advance_pos(Pos, <<"\\"/utf8>>),
Escaped
),
extract_string_literal(
Rest2,
<<<>/binary, Escaped/binary>>,
New_pos
);
{error, _} ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Unterminated escape sequence"/utf8>>}}
end;
{ok, {<<"\""/utf8>>, Rest@1}} ->
End_pos = advance_pos(Pos, <<"\""/utf8>>),
{ok, {Acc, Rest@1, End_pos}};
{ok, {Char, Rest@2}} ->
extract_string_literal(
Rest@2,
<>,
advance_pos(Pos, Char)
)
end.
-file("src/ghtml/parser.gleam", 897).
-spec extract_expression(binary(), integer(), binary(), ghtml@types:position()) -> {ok,
{binary(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
extract_expression(Input, Depth, Acc, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Unexpected end of input while parsing expression"/utf8>>}};
{ok, {<<"{"/utf8>>, Rest}} ->
extract_expression(
Rest,
Depth + 1,
<>,
advance_pos(Pos, <<"{"/utf8>>)
);
{ok, {<<"}"/utf8>>, Rest@1}} ->
case Depth of
0 ->
End_pos = advance_pos(Pos, <<"}"/utf8>>),
{ok, {Acc, Rest@1, End_pos}};
_ ->
extract_expression(
Rest@1,
Depth - 1,
<>,
advance_pos(Pos, <<"}"/utf8>>)
)
end;
{ok, {<<"\""/utf8>>, Rest@2}} ->
New_pos = advance_pos(Pos, <<"\""/utf8>>),
case extract_string_literal(Rest@2, <<""/utf8>>, New_pos) of
{ok, {Str, Remaining, After_pos}} ->
extract_expression(
Remaining,
Depth,
<<<<<>/binary, Str/binary>>/binary,
"\""/utf8>>,
After_pos
);
{error, Err} ->
{error, Err}
end;
{ok, {<<"("/utf8>>, Rest@3}} ->
extract_expression(
Rest@3,
Depth,
<>,
advance_pos(Pos, <<"("/utf8>>)
);
{ok, {<<")"/utf8>>, Rest@4}} ->
extract_expression(
Rest@4,
Depth,
<>,
advance_pos(Pos, <<")"/utf8>>)
);
{ok, {Char, Rest@5}} ->
extract_expression(
Rest@5,
Depth,
<>,
advance_pos(Pos, Char)
)
end.
-file("src/ghtml/parser.gleam", 451).
-spec parse_single_attribute(binary(), ghtml@types:position()) -> {ok,
{ghtml@types:attr(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
parse_single_attribute(Input, Pos) ->
case Input of
<<"@"/utf8, Rest/binary>> ->
Pos@1 = advance_pos(Pos, <<"@"/utf8>>),
{Event_name, Rest@1, New_pos} = extract_attr_name(
Rest,
<<""/utf8>>,
Pos@1
),
case Rest@1 of
<<"={"/utf8, After/binary>> ->
New_pos@1 = advance_pos_str(New_pos, <<"={"/utf8>>),
case extract_expression(After, 0, <<""/utf8>>, New_pos@1) of
{ok, {Handler, Remaining, End_pos}} ->
{ok,
{{event_attr, Event_name, Handler},
Remaining,
End_pos}};
{error, Err} ->
{error, Err}
end;
_ ->
{error,
{parse_error,
{span, New_pos, New_pos},
<<"Expected '={' after event attribute name"/utf8>>}}
end;
_ ->
{Attr_name, Rest@2, New_pos@2} = extract_attr_name(
Input,
<<""/utf8>>,
Pos
),
case Attr_name of
<<""/utf8>> ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Expected attribute name"/utf8>>}};
_ ->
case Rest@2 of
<<"={"/utf8, After@1/binary>> ->
New_pos@3 = advance_pos_str(
New_pos@2,
<<"={"/utf8>>
),
case extract_expression(
After@1,
0,
<<""/utf8>>,
New_pos@3
) of
{ok, {Expr, Remaining@1, End_pos@1}} ->
{ok,
{{dynamic_attr, Attr_name, Expr},
Remaining@1,
End_pos@1}};
{error, Err@1} ->
{error, Err@1}
end;
<<"=\""/utf8, After@2/binary>> ->
New_pos@4 = advance_pos_str(
New_pos@2,
<<"=\""/utf8>>
),
case extract_quoted_value(
After@2,
<<""/utf8>>,
New_pos@4
) of
{ok, {Value, Remaining@2, End_pos@2}} ->
{ok,
{{static_attr, Attr_name, Value},
Remaining@2,
End_pos@2}};
{error, Err@2} ->
{error, Err@2}
end;
<<"='"/utf8, After@3/binary>> ->
New_pos@5 = advance_pos_str(
New_pos@2,
<<"='"/utf8>>
),
case extract_single_quoted_value(
After@3,
<<""/utf8>>,
New_pos@5
) of
{ok, {Value@1, Remaining@3, End_pos@3}} ->
{ok,
{{static_attr, Attr_name, Value@1},
Remaining@3,
End_pos@3}};
{error, Err@3} ->
{error, Err@3}
end;
_ ->
{ok, {{boolean_attr, Attr_name}, Rest@2, New_pos@2}}
end
end
end.
-file("src/ghtml/parser.gleam", 983).
-spec parse_text(binary(), binary(), ghtml@types:position()) -> {binary(),
binary(),
ghtml@types:position()}.
parse_text(Input, Acc, Pos) ->
case Input of
<<"{{"/utf8, Rest/binary>> ->
parse_text(
Rest,
<>,
advance_pos_str(Pos, <<"{{"/utf8>>)
);
<<"}}"/utf8, Rest@1/binary>> ->
parse_text(
Rest@1,
<>,
advance_pos_str(Pos, <<"}}"/utf8>>)
);
<<"{"/utf8, _/binary>> ->
{Acc, Input, Pos};
<<"<"/utf8, _/binary>> ->
{Acc, Input, Pos};
<<"@import"/utf8, _/binary>> ->
{Acc, Input, Pos};
<<"@params"/utf8, _/binary>> ->
{Acc, Input, Pos};
<<""/utf8>> ->
{Acc, Input, Pos};
_ ->
case gleam_stdlib:string_pop_grapheme(Input) of
{ok, {Char, Rest@2}} ->
parse_text(
Rest@2,
<>,
advance_pos(Pos, Char)
);
{error, _} ->
{Acc, Input, Pos}
end
end.
-file("src/ghtml/parser.gleam", 1019).
-spec skip_html_comment(binary(), ghtml@types:position()) -> {ok,
{binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
skip_html_comment(Input, Pos) ->
case Input of
<<""/utf8>> ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Unterminated HTML comment"/utf8>>}};
<<"-->"/utf8, Rest/binary>> ->
End_pos = advance_pos_str(Pos, <<"-->"/utf8>>),
{ok, {Rest, End_pos}};
_ ->
case gleam_stdlib:string_pop_grapheme(Input) of
{ok, {Char, Rest@1}} ->
skip_html_comment(Rest@1, advance_pos(Pos, Char));
{error, _} ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Unterminated HTML comment"/utf8>>}}
end
end.
-file("src/ghtml/parser.gleam", 1045).
-spec is_whitespace_only(binary()) -> boolean().
is_whitespace_only(Text) ->
_pipe = Text,
_pipe@1 = gleam@string:to_graphemes(_pipe),
gleam@list:all(
_pipe@1,
fun(C) ->
(((C =:= <<" "/utf8>>) orelse (C =:= <<"\t"/utf8>>)) orelse (C =:= <<"\n"/utf8>>))
orelse (C =:= <<"\r"/utf8>>)
end
).
-file("src/ghtml/parser.gleam", 1051).
-spec skip_whitespace(binary(), ghtml@types:position()) -> {binary(),
ghtml@types:position()}.
skip_whitespace(Input, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{ok, {<<" "/utf8>>, Rest}} ->
skip_whitespace(Rest, advance_pos(Pos, <<" "/utf8>>));
{ok, {<<"\t"/utf8>>, Rest@1}} ->
skip_whitespace(Rest@1, advance_pos(Pos, <<"\t"/utf8>>));
{ok, {<<"\n"/utf8>>, Rest@2}} ->
skip_whitespace(Rest@2, advance_pos(Pos, <<"\n"/utf8>>));
{ok, {<<"\r"/utf8>>, Rest@3}} ->
skip_whitespace(Rest@3, advance_pos(Pos, <<"\r"/utf8>>));
_ ->
{Input, Pos}
end.
-file("src/ghtml/parser.gleam", 258).
-spec parse_close_tag(binary(), ghtml@types:position(), ghtml@types:position()) -> {ok,
{ghtml@types:token(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
parse_close_tag(Input, Start_pos, Pos) ->
{Tag_name, Rest, New_pos} = extract_tag_name(Input, <<""/utf8>>, Pos),
case Tag_name of
<<""/utf8>> ->
{error,
{parse_error, {span, Pos, Pos}, <<"Expected tag name"/utf8>>}};
_ ->
{Rest@1, New_pos@1} = skip_whitespace(Rest, New_pos),
case Rest@1 of
<<">"/utf8, Remaining/binary>> ->
End_pos = advance_pos(New_pos@1, <<">"/utf8>>),
Span = {span, Start_pos, End_pos},
{ok, {{html_close, Tag_name, Span}, Remaining, End_pos}};
_ ->
{error,
{parse_error,
{span, New_pos@1, New_pos@1},
<<"Expected '>' in closing tag"/utf8>>}}
end
end.
-file("src/ghtml/parser.gleam", 430).
-spec parse_attributes(
binary(),
ghtml@types:position(),
list(ghtml@types:attr())
) -> {ok, {list(ghtml@types:attr()), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
parse_attributes(Input, Pos, Attrs) ->
{Input@1, Pos@1} = skip_whitespace(Input, Pos),
case Input@1 of
<<">"/utf8, _/binary>> ->
{ok, {Attrs, Input@1, Pos@1}};
<<"/>"/utf8, _/binary>> ->
{ok, {Attrs, Input@1, Pos@1}};
<<""/utf8>> ->
{ok, {Attrs, Input@1, Pos@1}};
_ ->
case parse_single_attribute(Input@1, Pos@1) of
{ok, {Attr, Remaining, New_pos}} ->
parse_attributes(Remaining, New_pos, [Attr | Attrs]);
{error, Err} ->
{error, Err}
end
end.
-file("src/ghtml/parser.gleam", 285).
-spec parse_open_tag(binary(), ghtml@types:position(), ghtml@types:position()) -> {ok,
{ghtml@types:token(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
parse_open_tag(Input, Start_pos, Pos) ->
{Tag_name, Rest, New_pos} = extract_tag_name(Input, <<""/utf8>>, Pos),
case Tag_name of
<<""/utf8>> ->
{error,
{parse_error, {span, Pos, Pos}, <<"Expected tag name"/utf8>>}};
_ ->
case parse_attributes(Rest, New_pos, []) of
{ok, {Attrs, Remaining, Attr_end_pos}} ->
{Remaining@1, Attr_end_pos@1} = skip_whitespace(
Remaining,
Attr_end_pos
),
case Remaining@1 of
<<"/>"/utf8, After/binary>> ->
End_pos = advance_pos_str(
Attr_end_pos@1,
<<"/>"/utf8>>
),
Span = {span, Start_pos, End_pos},
{ok,
{{html_open,
Tag_name,
lists:reverse(Attrs),
true,
Span},
After,
End_pos}};
<<">"/utf8, After@1/binary>> ->
End_pos@1 = advance_pos(
Attr_end_pos@1,
<<">"/utf8>>
),
Span@1 = {span, Start_pos, End_pos@1},
{ok,
{{html_open,
Tag_name,
lists:reverse(Attrs),
false,
Span@1},
After@1,
End_pos@1}};
_ ->
{error,
{parse_error,
{span, Attr_end_pos@1, Attr_end_pos@1},
<<"Expected '>' or '/>' to close tag"/utf8>>}}
end;
{error, Err} ->
{error, Err}
end
end.
-file("src/ghtml/parser.gleam", 1061).
-spec extract_balanced_parens(
binary(),
integer(),
binary(),
ghtml@types:position()
) -> {ok, {binary(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
extract_balanced_parens(Input, Depth, Acc, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Unterminated parentheses"/utf8>>}};
{ok, {<<"("/utf8>>, Rest}} ->
extract_balanced_parens(
Rest,
Depth + 1,
<>,
advance_pos(Pos, <<"("/utf8>>)
);
{ok, {<<")"/utf8>>, Rest@1}} ->
case Depth of
0 ->
End_pos = advance_pos(Pos, <<")"/utf8>>),
{ok, {Acc, Rest@1, End_pos}};
_ ->
extract_balanced_parens(
Rest@1,
Depth - 1,
<>,
advance_pos(Pos, <<")"/utf8>>)
)
end;
{ok, {<<"\""/utf8>>, Rest@2}} ->
New_pos = advance_pos(Pos, <<"\""/utf8>>),
case extract_string_literal(Rest@2, <<""/utf8>>, New_pos) of
{ok, {Str, Remaining, After_pos}} ->
extract_balanced_parens(
Remaining,
Depth,
<<<<<>/binary, Str/binary>>/binary,
"\""/utf8>>,
After_pos
);
{error, Err} ->
{error, Err}
end;
{ok, {Char, Rest@3}} ->
extract_balanced_parens(
Rest@3,
Depth,
<>,
advance_pos(Pos, Char)
)
end.
-file("src/ghtml/parser.gleam", 168).
-spec parse_import(binary(), ghtml@types:position(), ghtml@types:position()) -> {ok,
{ghtml@types:token(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
parse_import(Input, Start_pos, Pos) ->
case Input of
<<"("/utf8, Rest/binary>> ->
Pos@1 = advance_pos(Pos, <<"("/utf8>>),
case extract_balanced_parens(Rest, 0, <<""/utf8>>, Pos@1) of
{ok, {Content, Remaining, End_pos}} ->
Span = {span, Start_pos, End_pos},
{ok, {{import, Content, Span}, Remaining, End_pos}};
{error, Err} ->
{error, Err}
end;
_ ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Expected '(' after @import"/utf8>>}}
end.
-file("src/ghtml/parser.gleam", 191).
-spec parse_params(binary(), ghtml@types:position(), ghtml@types:position()) -> {ok,
{ghtml@types:token(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
parse_params(Input, Start_pos, Pos) ->
case Input of
<<"("/utf8, Rest/binary>> ->
Pos@1 = advance_pos(Pos, <<"("/utf8>>),
case extract_balanced_parens(Rest, 0, <<""/utf8>>, Pos@1) of
{ok, {Content, Remaining, End_pos}} ->
Params = parse_param_list(Content),
Span = {span, Start_pos, End_pos},
{ok, {{params, Params, Span}, Remaining, End_pos}};
{error, Err} ->
{error, Err}
end;
_ ->
{error,
{parse_error,
{span, Pos, Pos},
<<"Expected '(' after @params"/utf8>>}}
end.
-file("src/ghtml/parser.gleam", 868).
-spec extract_pattern(binary(), binary(), ghtml@types:position()) -> {ok,
{binary(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
extract_pattern(Input, Acc, Pos) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
{error,
{parse_error, {span, Pos, Pos}, <<"Unterminated pattern"/utf8>>}};
{ok, {<<"}"/utf8>>, Rest}} ->
End_pos = advance_pos(Pos, <<"}"/utf8>>),
{ok, {Acc, Rest, End_pos}};
{ok, {<<"("/utf8>>, Rest@1}} ->
New_pos = advance_pos(Pos, <<"("/utf8>>),
case extract_balanced_parens(Rest@1, 0, <<""/utf8>>, New_pos) of
{ok, {Inner, Remaining, After_pos}} ->
extract_pattern(
Remaining,
<<<<<>/binary, Inner/binary>>/binary,
")"/utf8>>,
After_pos
);
{error, Err} ->
{error, Err}
end;
{ok, {Char, Rest@2}} ->
extract_pattern(
Rest@2,
<>,
advance_pos(Pos, Char)
)
end.
-file("src/ghtml/parser.gleam", 686).
-spec parse_brace_content(
binary(),
ghtml@types:position(),
ghtml@types:position()
) -> {ok, {ghtml@types:token(), binary(), ghtml@types:position()}} |
{error, ghtml@types:parse_error()}.
parse_brace_content(Input, Start_pos, Pos) ->
case Input of
<<"#if "/utf8, Rest/binary>> ->
Pos@1 = advance_pos_str(Pos, <<"#if "/utf8>>),
case extract_expression(Rest, 0, <<""/utf8>>, Pos@1) of
{ok, {Condition, Remaining, End_pos}} ->
Span = {span, Start_pos, End_pos},
{ok,
{{if_start, gleam@string:trim(Condition), Span},
Remaining,
End_pos}};
{error, Err} ->
{error, Err}
end;
<<":else}"/utf8, Rest@1/binary>> ->
End_pos@1 = advance_pos_str(Pos, <<":else}"/utf8>>),
Span@1 = {span, Start_pos, End_pos@1},
{ok, {{'else', Span@1}, Rest@1, End_pos@1}};
<<"/if}"/utf8, Rest@2/binary>> ->
End_pos@2 = advance_pos_str(Pos, <<"/if}"/utf8>>),
Span@2 = {span, Start_pos, End_pos@2},
{ok, {{if_end, Span@2}, Rest@2, End_pos@2}};
<<"#each "/utf8, Rest@3/binary>> ->
Pos@2 = advance_pos_str(Pos, <<"#each "/utf8>>),
case parse_each_header(Rest@3, Pos@2) of
{ok, {Collection, Item, Index, Remaining@1, End_pos@3}} ->
Span@3 = {span, Start_pos, End_pos@3},
{ok,
{{each_start, Collection, Item, Index, Span@3},
Remaining@1,
End_pos@3}};
{error, Err@1} ->
{error, Err@1}
end;
<<"/each}"/utf8, Rest@4/binary>> ->
End_pos@4 = advance_pos_str(Pos, <<"/each}"/utf8>>),
Span@4 = {span, Start_pos, End_pos@4},
{ok, {{each_end, Span@4}, Rest@4, End_pos@4}};
<<"#case "/utf8, Rest@5/binary>> ->
Pos@3 = advance_pos_str(Pos, <<"#case "/utf8>>),
case extract_expression(Rest@5, 0, <<""/utf8>>, Pos@3) of
{ok, {Expr, Remaining@2, End_pos@5}} ->
Span@5 = {span, Start_pos, End_pos@5},
{ok,
{{case_start, gleam@string:trim(Expr), Span@5},
Remaining@2,
End_pos@5}};
{error, Err@2} ->
{error, Err@2}
end;
<<":"/utf8, Rest@6/binary>> ->
Pos@4 = advance_pos(Pos, <<":"/utf8>>),
case extract_pattern(Rest@6, <<""/utf8>>, Pos@4) of
{ok, {Pattern, Remaining@3, End_pos@6}} ->
Span@6 = {span, Start_pos, End_pos@6},
{ok,
{{case_pattern, Pattern, Span@6},
Remaining@3,
End_pos@6}};
{error, Err@3} ->
{error, Err@3}
end;
<<"/case}"/utf8, Rest@7/binary>> ->
End_pos@7 = advance_pos_str(Pos, <<"/case}"/utf8>>),
Span@7 = {span, Start_pos, End_pos@7},
{ok, {{case_end, Span@7}, Rest@7, End_pos@7}};
_ ->
case extract_expression(Input, 0, <<""/utf8>>, Pos) of
{ok, {Expr@1, Remaining@4, End_pos@8}} ->
Span@8 = {span, Start_pos, End_pos@8},
{ok, {{expr, Expr@1, Span@8}, Remaining@4, End_pos@8}};
{error, Err@4} ->
{error, Err@4}
end
end.
-file("src/ghtml/parser.gleam", 53).
-spec tokenize_loop(binary(), ghtml@types:position(), list(ghtml@types:token())) -> {ok,
list(ghtml@types:token())} |
{error, list(ghtml@types:parse_error())}.
tokenize_loop(Input, Pos, Tokens) ->
case Input of
<<""/utf8>> ->
{ok, Tokens};
<<"@import"/utf8, Rest/binary>> ->
Start_pos = Pos,
Pos@1 = advance_pos_str(Pos, <<"@import"/utf8>>),
case parse_import(Rest, Start_pos, Pos@1) of
{ok, {Token, Remaining, New_pos}} ->
tokenize_loop(Remaining, New_pos, [Token | Tokens]);
{error, Err} ->
{error, [Err]}
end;
<<"@params"/utf8, Rest@1/binary>> ->
Start_pos@1 = Pos,
Pos@2 = advance_pos_str(Pos, <<"@params"/utf8>>),
case parse_params(Rest@1, Start_pos@1, Pos@2) of
{ok, {Token@1, Remaining@1, New_pos@1}} ->
tokenize_loop(Remaining@1, New_pos@1, [Token@1 | Tokens]);
{error, Err@1} ->
{error, [Err@1]}
end;
<<"