-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(_, []) -> [].