wip name cleanups
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
% @doc
|
||||
% File ::= Block(TopDecl)
|
||||
-record(ast_file,
|
||||
{top_decls = none :: none | [top_decl()]}).
|
||||
|
||||
|
||||
-type ast() :: #ast_file{}
|
||||
| top_decl()
|
||||
| #ast_nyi{}
|
||||
.
|
||||
|
||||
%% Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
%% | 'record' Id ['(' TVar* ')'] '=' RecordType
|
||||
%% | 'datatype' Id ['(' TVar* ')'] '=' DataType
|
||||
%% | 'let' Id [':' Type] '=' Expr
|
||||
%% | (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
|
||||
%% | Using
|
||||
%-record(ast_type_alias,
|
||||
% {name = none :: none | string(),
|
||||
% tvars = none :: none | [string()],
|
||||
% rewrites_to = none :: none | ast_type()}).
|
||||
|
||||
|
||||
-type gulp_target()
|
||||
:: ast_file
|
||||
| top_decl
|
||||
| ast_ct
|
||||
| ast_nyi
|
||||
.
|
||||
|
||||
% gulp means it must consume all input
|
||||
-spec gulp(AstTarget, SigTokens) -> Perhaps
|
||||
when AstTarget :: gulp_target(),
|
||||
SigTokens :: [sfc_token()],
|
||||
Perhaps :: {gulp, ast()}
|
||||
| {error, sfc_err()}.
|
||||
|
||||
gulp(ast_file, Tokens) ->
|
||||
gulp_file(Tokens);
|
||||
gulp(top_decl, Tokens) ->
|
||||
Targets = [ast_ct,
|
||||
ast_nyi],
|
||||
gulp_oneof(Targets, Tokens);
|
||||
gulp(ast_ct, Tokens) ->
|
||||
gulp_ct(#ast_ct{}, Tokens);
|
||||
gulp(ast_nyi, Tokens) ->
|
||||
{gulp, #ast_nyi{tokens = Tokens}};
|
||||
gulp({block_of, X}, Tokens) ->
|
||||
{barf, ItemChunks, []} = sfc_token_chunks:barf(block_as_items, Tokens),
|
||||
gulp_block_of(X, ItemChunks);
|
||||
gulp(Nyi, Tokens) ->
|
||||
Msg = io_lib:format("sfc_ast:gulp/2: unknown target: ~p", [Nyi]),
|
||||
Err = #sfc_err{atom = gulp_nyi,
|
||||
string = Msg,
|
||||
extra = [{target, Nyi}, {tokens, Tokens}]},
|
||||
{error, Err}.
|
||||
|
||||
|
||||
|
||||
% FIXME: payable and main need to be in that order i think
|
||||
gulp_ct(Ast = #ast_ct{payable = none}, Tokens) ->
|
||||
case Tokens of
|
||||
[#sfc_token{string = "payable", type = kwd} | NewTokens] ->
|
||||
gulp_ct(Ast#ast_ct{payable = payable}, NewTokens);
|
||||
_ ->
|
||||
gulp_ct(Ast#ast_ct{payable = false}, Tokens)
|
||||
end;
|
||||
gulp_ct(Ast = #ast_ct{main = none}, Tokens) ->
|
||||
case Tokens of
|
||||
[#sfc_token{string = "main", type = kwd} | NewTokens] ->
|
||||
gulp_ct(Ast#ast_ct{main = main}, NewTokens);
|
||||
_ ->
|
||||
gulp_ct(Ast#ast_ct{main = false}, Tokens)
|
||||
end;
|
||||
gulp_ct(Ast = #ast_ct{contract = none}, Tokens) ->
|
||||
case Tokens of
|
||||
[#sfc_token{string = "contract", type = kwd} | NewTokens] ->
|
||||
gulp_ct(Ast#ast_ct{contract = contract}, NewTokens);
|
||||
% FIXME: reject logic applies to choice of branch, therefore
|
||||
% should be contained in branchpoint code
|
||||
_ ->
|
||||
reject
|
||||
%[#sfc_token{pos = P, string = S} | _] ->
|
||||
% {error, #sfc_err{atom = no_kwd_contract,
|
||||
% extra = [{pos, P},
|
||||
% {expecting, "contract"},
|
||||
% {got, S},
|
||||
% {ast, Ast},
|
||||
% {tokens, Tokens}]}};
|
||||
%[] ->
|
||||
% {error, #sfc_err{atom = no_kwd_contract,
|
||||
% extra = [{pos, none},
|
||||
% {expecting, "contract"},
|
||||
% {got, eof},
|
||||
% {ast, Ast},
|
||||
% {tokens, Tokens}]}}
|
||||
end;
|
||||
gulp_ct(Ast = #ast_ct{name = none}, Tokens) ->
|
||||
case Tokens of
|
||||
[#sfc_token{string = Name, type = con} | NewTokens] ->
|
||||
gulp_ct(Ast#ast_ct{name = Name}, NewTokens);
|
||||
_ ->
|
||||
reject
|
||||
end;
|
||||
gulp_ct(Ast = #ast_ct{implements = none}, Tokens) ->
|
||||
case slurp_ct_impls(Tokens) of
|
||||
{slurp, Names, NewTokens} ->
|
||||
gulp_ct(Ast#ast_ct{implements = {':', Names}}, NewTokens);
|
||||
reject ->
|
||||
gulp_ct(Ast#ast_ct{implements = {':', []}}, Tokens);
|
||||
Poison -> Poison
|
||||
end;
|
||||
gulp_ct(Ast = #ast_ct{eq = none}, Tokens) ->
|
||||
case Tokens of
|
||||
[#sfc_token{string = "=", type = op} | NewTokens] ->
|
||||
gulp_ct(Ast#ast_ct{eq = '='}, NewTokens);
|
||||
_ ->
|
||||
{error, #sfc_err{atom = no_eq}}
|
||||
end;
|
||||
gulp_ct(Ast = #ast_ct{decls = none}, Tokens) ->
|
||||
Decls = [gulp(decl, Item) || Item <- sfc_token_chunks:unsafe_block_to_items(Tokens)],
|
||||
{gulp, Ast#ast_ct{decls = Decls}};
|
||||
gulp_ct(_, _) ->
|
||||
reject.
|
||||
|
||||
|
||||
slurp_ct_impls([#sfc_token{string = ":", type = op},
|
||||
#sfc_token{string = Con1, type = con}
|
||||
| Rest]) ->
|
||||
slurp_ct_impls2(Rest, [Con1]);
|
||||
slurp_ct_impls(_) ->
|
||||
reject.
|
||||
|
||||
slurp_ct_impls2([#sfc_token{string = ",", type = punct},
|
||||
#sfc_token{string = Con1, type = con}
|
||||
| Rest],
|
||||
Acc) ->
|
||||
slurp_ct_impls2(Rest, [Con1 | Acc]);
|
||||
slurp_ct_impls2(Rest, Names) ->
|
||||
{slurp, lists:reverse(Names), Rest}.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-spec gulp_file(SigTokens) -> Perhaps
|
||||
when SigTokens :: [sfc_token()],
|
||||
Perhaps :: {gulp, #ast_file{}}
|
||||
| {error, sfc_err()}.
|
||||
% @private
|
||||
% `file` enforces that the entire SigTokens is one
|
||||
% block, chokes otherwise
|
||||
|
||||
gulp_file([]) ->
|
||||
{error, #sfc_err{atom = empty_file}};
|
||||
gulp_file(FileTokens = [#sfc_token{pos = FilePos} | _]) ->
|
||||
case sfc_token_chunks:barf(block, FileTokens) of
|
||||
% happy path: got the whole file back
|
||||
{barf, FileTokens, []} ->
|
||||
gulp_full_file(FileTokens);
|
||||
% sad path: block terminated
|
||||
{barf, _, [#sfc_token{pos = EndPos}]} ->
|
||||
Msg = io_lib:format("block starting at ~p ends at ~p instead of EOF",
|
||||
[FilePos, EndPos]),
|
||||
{error, #sfc_err{atom = bad_file,
|
||||
string = Msg}};
|
||||
Nyi ->
|
||||
{error, #sfc_err{atom = bad_file_nyi, extra = Nyi}}
|
||||
end.
|
||||
|
||||
|
||||
% FIXME: need to rethink types here in order to handle syntax errors
|
||||
% from different blocks independently.
|
||||
|
||||
% file = block(top_decl)
|
||||
gulp_full_file(BlockTokens) ->
|
||||
ItemChunks = sfc_token_chunks:unsafe_block_to_items(BlockTokens),
|
||||
gulp_file_decls([], [], ItemChunks).
|
||||
|
||||
|
||||
gulp_file_decls(Decls, Errs, [DeclTokens | Rest]) ->
|
||||
case gulp(top_decl, DeclTokens) of
|
||||
{gulp, NewDecl} ->
|
||||
gulp_file_decls([NewDecl | Decls], Errs, Rest);
|
||||
reject ->
|
||||
ErrPos = sfc_token_chunks:start_pos(DeclTokens),
|
||||
NewErr = #sfc_err{atom = bad_top_decl,
|
||||
extra = [{tokens, DeclTokens},
|
||||
{pos, ErrPos}]},
|
||||
gulp_file_decls(Decls, [NewErr | Errs], Rest);
|
||||
Poison ->
|
||||
gulp_file_decls(Decls, [Poison | Errs], Rest)
|
||||
end;
|
||||
% end of block
|
||||
gulp_file_decls(Decls, _Errs = [], _Input = []) ->
|
||||
{gulp, #ast_file{top_decls = lists:reverse(Decls)}};
|
||||
gulp_file_decls(_Decls, Errs, _Input = []) ->
|
||||
{error, #sfc_err{atom = many,
|
||||
extra = Errs}}.
|
||||
Reference in New Issue
Block a user