Files
sfc/scratch/sfc_group_tokens.erl
T
2026-06-11 18:23:00 -07:00

95 lines
2.4 KiB
Erlang

-module(sfc_group_tokens).
-export_type([
]).
-export([
group_tokens/1
]).
-include("sfc.hrl").
-spec group_tokens(Tokens) -> Result
when Tokens :: [sfc_token()],
Result :: {ok, Groups}
| {error, Reason},
Groups :: [TokenGroup],
TokenGroup :: sfc_token()
| #sfc_tg_list{},
Reason :: any().
group_tokens(Tokens) ->
group_tokens([], Tokens).
group_tokens(Stack, Tokens = [_ | _]) ->
case token_or_group(Tokens) of
{push, Item, NewTokens} ->
group_tokens([Item | Stack], NewTokens);
Error ->
Error
end;
group_tokens(Stack, []) ->
{ok, lists:reverse(Stack)}.
% erlang's type language is lacking here...
% items are always a list of sfc_token_group_items
% placeholder type
-type sfc_tg_item_() :: any().
% tg = token group
% {start_line, indent} should always equal the Pos of the first token
-record(sfc_tg_block,
{start_line = none :: none | pos_integer(),
indent = none :: none | pos_integer(),
items = none :: none | {stack, [sfc_tg_item_()]} | [sfc_tg_item_()]}).
% delist = delimited list (...) [...], {...}
%
% don't even comma-separate values, just make sure
-record(sfc_tg_delist,
{open = none :: none | '(' | '[' | '{',
items = none :: none | {stack, [sfc_tg_item()]} | [sfc_tg_item()],
close = none :: none | ')' | ']' | '}',
-type sfc_tg_item() :: sfc_token(),
| #sfc_tg_block{}
| #sfc_tg_round{}
| #sfc_.
-type sfc_tg() :: [sfc_tg_item()].
-spec token_or_group(Tokens) -> Result
when Tokens :: [sfc_token()],
Result :: {push, Item, NewTokens}
| {error, Reason}
Item :: sfc_token()
| {block, IndentLevel :: pos_integer(),
,
token_or_group(Tokens) ->
groupist_order() ->
[round, square, curly, block].
match_groupists([Groupist | Rest], Tokens) ->
case groupist(Grupist, Tokens) of
Match = {groupmatch, _, _} ->
Match
no_groupmatch ->
match_groupists(Rest, Tokens);
Error ->
Error
end;
match_groupists(_, []) ->
{ok, []};
match_groupists([], [#sfc_token{pos = Pos} | _}) ->
{error, {cannot_make_groupist_decision, Pos}}.