95 lines
2.4 KiB
Erlang
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}}.
|