-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, {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, {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]). -spec gulp(Target, Signal) -> Result when Target :: syntax_target(), Signal :: [tk()], Result :: {gulp, syntax_stem()} | {error, any()}. 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}; % Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias % | 'record' Id ['(' TVar* ')'] '=' RecordType % | 'datatype' Id ['(' TVar* ')'] '=' DataType % | 'let' Id [':' Type] '=' Expr % | (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl) % | Using gulp(decl, Sig) -> NewTarget = case strings(1, Sig) of ["type"] -> type; ["record"] -> record; ["datatype"] -> datatype; ["let"] -> 'let'; ["using"] -> using; _ -> fn end, gulp(NewTarget, Sig); gulp(NyiTarget, Sig) -> error({nyi, [?MODULE, gulp, NyiTarget, Sig]}). %% ['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); _ -> 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{str = Irregar} | _] -> error(illegal_contract_name, Irregar); [] -> error(no_contract_name) end; slurp(M = #ct{impls = none}, Sig) -> case Sig of [#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}; _ -> error("where the fuck my = be at nigga") 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(BadMeta, BadTokens) -> error({nyi, [?MODULE, slurp, BadMeta, BadTokens]}). 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(_, []) -> [].