Current section
Files
Jump to
Current section
Files
src/handles@parser.erl
-module(handles@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([run/2]).
-export_type([parse_error/0, ast/0]).
-type parse_error() :: {unbalanced_block, integer(), integer(), binary()} |
{unknown_block_kind, integer(), integer(), binary()}.
-type ast() :: {constant, binary()} |
{property, list(binary())} |
{block, binary(), list(binary()), list(ast())}.
-spec validation_pass(list(handles@lexer:token()), list(binary())) -> list({ok,
handles@lexer:token()} |
{error, parse_error()}).
validation_pass(Tokens, Valid_blocks) ->
_pipe = Tokens,
gleam@list:map(_pipe, fun(It) -> case It of
{block_start, Start, End, Kind, _} ->
case gleam@list:contains(Valid_blocks, Kind) of
true ->
{ok, It};
false ->
{error, {unknown_block_kind, Start, End, Kind}}
end;
_ ->
{ok, It}
end end).
-spec balance_pass(list({ok, handles@lexer:token()} | {error, parse_error()})) -> list({ok,
handles@lexer:token()} |
{error, parse_error()}).
balance_pass(Tokens) ->
{Out@1, Stack@1} = begin
_pipe = Tokens,
gleam@list:fold(
_pipe,
{[], []},
fun(Acc, It) ->
{Out, Stack} = Acc,
case It of
{ok, {block_start, _, _, Kind, _}} ->
{[It | Out], [Kind | Stack]};
{ok, {block_end, Start, End, Kind@1}} ->
case gleam@list:first(Stack) of
{ok, Top} when Top =:= Kind@1 ->
case gleam@list:rest(Stack) of
{ok, Rest} ->
{[It | Out], Rest};
_ ->
{[{error,
{unbalanced_block,
Start,
End,
Kind@1}} |
Out],
[]}
end;
_ ->
case gleam@list:rest(Stack) of
{ok, Rest@1} ->
{[It | Out], Rest@1};
_ ->
{[{error,
{unbalanced_block,
Start,
End,
Kind@1}} |
Out],
[]}
end
end;
_ ->
{[It | Out], Stack}
end
end
)
end,
gleam@list:concat(
[Out@1,
gleam@list:map(
Stack@1,
fun(It@1) -> {error, {unbalanced_block, -1, -1, It@1}} end
)]
).
-spec ast_transform_pass(list(handles@lexer:token()), list(ast())) -> list(ast()).
ast_transform_pass(Tokens, Ast) ->
case Tokens of
[] ->
lists:reverse(Ast);
[Head | Tail] ->
case Head of
{constant, _, _, Value} ->
ast_transform_pass(Tail, [{constant, Value} | Ast]);
{property, _, _, Path} ->
ast_transform_pass(Tail, [{property, Path} | Ast]);
{block_start, _, _, Kind, Path@1} ->
Children = ast_transform_pass(Tail, []),
ast_transform_pass(
gleam@list:drop(Tail, erlang:length(Children)),
[{block, Kind, Path@1, Children} | Ast]
);
{block_end, _, _, _} ->
lists:reverse(Ast)
end
end.
-spec run(list(handles@lexer:token()), list(binary())) -> {ok, list(ast())} |
{error, list(parse_error())}.
run(Tokens, Valid_blocks) ->
case begin
_pipe = Tokens,
_pipe@1 = validation_pass(_pipe, Valid_blocks),
_pipe@2 = balance_pass(_pipe@1),
gleam@result:partition(_pipe@2)
end of
{[{constant, _, _, <<""/utf8>>} | Tokens@1], []} ->
{ok,
begin
_pipe@3 = Tokens@1,
ast_transform_pass(_pipe@3, [])
end};
{Tokens@2, []} ->
{ok,
begin
_pipe@4 = Tokens@2,
ast_transform_pass(_pipe@4, [])
end};
{_, Err} ->
{error, Err}
end.