178 lines
5.8 KiB
Erlang
178 lines
5.8 KiB
Erlang
-module(gsc_test_ytree).
|
|
|
|
-export([main/0]).
|
|
-include("$gsc_include/gsc.hrl").
|
|
|
|
main() ->
|
|
Src =
|
|
"""
|
|
contract Foo =
|
|
type foo = bar
|
|
""",
|
|
handle_src_str(Src).
|
|
|
|
-type syntax_target() :: signal
|
|
| file
|
|
| {block_of, syntax_target()}
|
|
| top_decl
|
|
| contract
|
|
| interface
|
|
| namespace
|
|
| '@compiler'
|
|
| include
|
|
| using
|
|
.
|
|
|
|
-record(ct, {ok = ok :: ok | {error, any()},
|
|
payable = none :: none | false | true,
|
|
main = none :: none | false | true,
|
|
contract = none :: none | tk(),
|
|
con = none :: none | tk(),
|
|
impls = none :: none | false | {true, [tk()]},
|
|
'=' = none :: none | tk()}).
|
|
|
|
%% @doc This is all the stuff needed to be consumed before parsin
|
|
%% anything in the contract
|
|
-type contract_meta() :: #ct{}.
|
|
|
|
|
|
%% @doc
|
|
%% This is all the stuff that has to be parsed before actual parsing
|
|
%% can begin.
|
|
-type stem_meta() :: none
|
|
| contract_meta().
|
|
|
|
% @doc ys = syntax stem
|
|
-record(ys, {ok = ok :: ok | {error, any()},
|
|
target = signal :: syntax_target(),
|
|
signal :: [tk()],
|
|
stem_meta :: stem_meta(),
|
|
forest :: [#ys{}]}).
|
|
|
|
-type syntax_stem() :: #ys{}.
|
|
|
|
|
|
handle_src_str(SrcStr) ->
|
|
Sig = gsc:unsafe_signal_from_string(SrcStr),
|
|
Result = gulp(file, Sig),
|
|
io:format("~tp~n", [Result]).
|
|
|
|
|
|
gulp(file, Sig) ->
|
|
gulp({block_of, top_decl}, Sig);
|
|
gulp({block_of, X}, Sig) ->
|
|
{gulp, BlockItems} = gsc_signal:gulp_block_items(Sig),
|
|
#ys{target = {block_of, X},
|
|
signal = Sig,
|
|
stem_meta = none,
|
|
forest = [gulp(X, Item) || Item <- BlockItems]};
|
|
gulp(top_decl, Sig) ->
|
|
% TopDecl ::= ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl)
|
|
% | 'contract' 'interface' Con [Implement] '=' Block(Decl)
|
|
% | 'namespace' Con '=' Block(Decl)
|
|
% | '@compiler' PragmaOp Version
|
|
% | 'include' String
|
|
% | Using
|
|
NewTarget =
|
|
case gsc_tokens:strings(3, Sig) of
|
|
["namespace", _, _] -> namespace;
|
|
["@compiler", _, _] -> '@compiler';
|
|
["include", _, _] -> include;
|
|
["using", _, _] -> using;
|
|
["payable", "main", "contract"] -> contract;
|
|
["payable", "contract", "interface"] -> interface;
|
|
["payable", "contract", _] -> contract;
|
|
["contract", "interface", _] -> interface;
|
|
["contract", _, _] -> contract;
|
|
["main", "contract", _] -> contract;
|
|
["main", "payable", "contract"] -> contract
|
|
end,
|
|
gulp(NewTarget, Sig);
|
|
gulp(contract, Sig) ->
|
|
{slurp, CtMeta, BlockSignal} = slurp(#ct{}, Sig),
|
|
{gulp, BlockItems} = gsc_signal:gulp_block_items(BlockSignal),
|
|
Forest = [gulp(decl, Item) || Item <- BlockItems],
|
|
#ys{target = contract,
|
|
signal = Sig,
|
|
stem_meta = CtMeta,
|
|
forest = Forest};
|
|
gulp(NyiTarget, Sig) ->
|
|
#ys{target = NyiTarget,
|
|
signal = Sig,
|
|
stem_meta = {nyi, NyiTarget},
|
|
forest = []}.
|
|
|
|
|
|
%% ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl)
|
|
slurp(Meta = #ct{payable = none, main = none}, Sig) ->
|
|
%% nato phonetic alphabet
|
|
{Pa, Mi, No} =
|
|
case gsc_tokens:strings(2, Sig) of
|
|
["payable", "main"] -> {true, true, 2};
|
|
["main", "payable"] -> {true, true, 2};
|
|
["payable", _] -> {true, false, 1};
|
|
["main", _] -> {false, true, 1};
|
|
_ -> {false, false, 0}
|
|
end,
|
|
NewMeta = Meta#ct{payable = Pa, main = Mi},
|
|
NewSig = take(No, Sig),
|
|
slurp(NewMeta, NewSig);
|
|
slurp(M = #ct{contract = none}, Sig) ->
|
|
case Sig of
|
|
[Tk = #tk{str = "contract"} | Rest] ->
|
|
slurp(M#ct{contract = Tk}, Rest);
|
|
_ ->
|
|
M#ct{ok = {error, no_keyword_contract}}
|
|
end;
|
|
slurp(M = #ct{con = none}, Sig) ->
|
|
case Sig of
|
|
[Tk = #tk{shape = con} | Rest] ->
|
|
slurp(M#ct{con = Tk}, Rest);
|
|
[Tk = #tk{str = Irregar} | _] ->
|
|
M#ct{ok = {error, {illegal_contract_name, Irregar}}};
|
|
[] ->
|
|
M#ct{ok = {error, no_contract_name}}
|
|
end;
|
|
slurp(M = #ct{impls = none}, Sig) ->
|
|
case Sig of
|
|
[Tk = #tk{str = ":"} | Rest] ->
|
|
{slurp, Impls, NewRest} = slurp({sep1, con, ","}, Rest),
|
|
NewM = M#ct{impls = {true, Impls}},
|
|
slurp(NewM, NewRest);
|
|
_ ->
|
|
slurp(M#ct{impls = false}, Sig)
|
|
end;
|
|
slurp(M = #ct{'=' = none}, Sig) ->
|
|
case Sig of
|
|
[Tk = #tk{str = "="} | Rest] ->
|
|
{slurp, M#ct{'=' = Tk}, Rest};
|
|
_ ->
|
|
M#ct{ok = {error, no_token_eq}}
|
|
end;
|
|
slurp({sep1, TkShape, SepByStr}, Tks) ->
|
|
case Tks of
|
|
[Tk = #tk{shape = TkShape} | Rest] ->
|
|
slurp_sep1_ii([Tk], TkShape, SepByStr, Rest);
|
|
_ ->
|
|
{error, irregar}
|
|
end;
|
|
slurp(M, Tks) ->
|
|
{slurp, {nyi, M}, Tks}.
|
|
|
|
|
|
slurp_sep1_ii(Stk, TkShape, SepByStr, Sig) ->
|
|
case Sig of
|
|
[#tk{str = SepByStr}, T = #tk{shape = TkShape} | Rest] ->
|
|
slurp_sep1_ii([T | Stk], TkShape, SepByStr, Rest);
|
|
_ ->
|
|
{slurp, lists:reverse(Stk), Sig}
|
|
end.
|
|
|
|
strings(N, Tks) ->
|
|
gsc_tokens:strings(N, Tks).
|
|
|
|
|
|
take(N, [_ | Rest]) when N >= 1 -> take(N-1, Rest);
|
|
take(0, List) -> List;
|
|
take(_, []) -> [].
|