From 654ff01e9864869e5bb54b8b16322c276a249022 Mon Sep 17 00:00:00 2001 From: Peter Harpending Date: Tue, 11 Aug 2026 23:45:00 -0600 Subject: [PATCH] [wip] ytree works on its 1 test example --- src/gsc_signal.erl | 9 ++- src/gsc_tokens.erl | 50 ++++++++++++---- test/gsc_test_ytree.erl | 128 ++++++++++++++++++++++++++++++++-------- 3 files changed, 143 insertions(+), 44 deletions(-) diff --git a/src/gsc_signal.erl b/src/gsc_signal.erl index 1d55e50..3776eba 100644 --- a/src/gsc_signal.erl +++ b/src/gsc_signal.erl @@ -38,11 +38,10 @@ is_block([#tk{pos = {_, BCol}} | Rest]) -> -spec gulp_block_items(Signal) -> Result when - Signal :: [tk()], - Result :: {gulp, Items} - | {error, any()}, - Items :: [Signal], - NewSignal :: Signal. + Signal :: [tk()], + Result :: {gulp, [Item]} + | {error, any()}, + Item :: Signal. gulp_block_items(S) -> case is_block(S) of diff --git a/src/gsc_tokens.erl b/src/gsc_tokens.erl index 150bd92..9de362e 100644 --- a/src/gsc_tokens.erl +++ b/src/gsc_tokens.erl @@ -29,7 +29,7 @@ take_while/3, take_block/1, take_block_item/1, - strings/2, + strings/2, strs/2, slurp_plist/1 ]). @@ -43,6 +43,7 @@ very_stable_string/1, very_stable_characters/1, tokens_from_iolist/1, + tokens_from_string/1, tokens/1, slurp_token/2, slurp_token_shapes/3, @@ -57,18 +58,32 @@ % API: functions %======================================================= --spec strings(N, Tokens) -> AtMostNStrings - when N :: non_neg_integer(), +-spec strs(N, Tokens) -> AtMostNStrings + when N :: infinity | non_neg_integer(), Tokens :: [tk()], AtMostNStrings :: [string()]. -% @doc return the strings of the first N tokens +%% @equiv `strings/2' -strings(N, [#tk{str = S} | Rest]) when is_integer(N), N >= 1 -> - [S | strings(N-1, Rest)]; -strings(_, []) -> - []; -strings(0, _) -> - []. +strs(N, Tks) -> strings(N, Tks). + + + +-spec strings(N, Tokens) -> AtMostNStrings + when N :: infinity | non_neg_integer(), + Tokens :: [tk()], + AtMostNStrings :: [string()]. +%% @doc return the strings of the first N tokens + +strings(N, Tks) when is_integer(N) -> + strsn(N, Tks); +strings(infinity, Tks) -> + [Str || #tk{str = Str} <- Tks]. + + + +strsn(N, [#tk{str = Str} | Rest]) when N >= 1 -> [Str | strsn(N-1, Rest)]; +strsn(_, []) -> []; +strsn(0, _) -> []. % used by parser @@ -77,8 +92,7 @@ strings(0, _) -> % % BLOCK = % foo -% ... -% bar +% ... bar % ... % baz % ... @@ -362,10 +376,20 @@ very_stable_codepoints(S) -> | {error, gsc_err()}, Tokens :: [tk()]. -% @doc alias for tokens/1 +%% @equiv `tokens/1' tokens_from_iolist(S) -> tokens(S). +-spec tokens_from_string(SrcStr) -> Result when + SrcStr :: iolist(), + Result :: {ok, Tokens} + | {error, gsc_err()}, + Tokens :: [tk()]. + +%% @equiv `tokens/1' +tokens_from_string(S) -> tokens(S). + + -spec tokens(SrcStr) -> Result diff --git a/test/gsc_test_ytree.erl b/test/gsc_test_ytree.erl index 8c5d9af..90aac54 100644 --- a/test/gsc_test_ytree.erl +++ b/test/gsc_test_ytree.erl @@ -4,7 +4,11 @@ -include("$gsc_include/gsc.hrl"). main() -> - Src = "type foo = bar", + Src = + """ + contract Foo = + type foo = bar + """, handle_src_str(Src). -type syntax_target() :: signal @@ -19,16 +23,13 @@ main() -> | using . --type tk() :: gsc_token:token(). - - --record(ct, {ok = ok :: ok | {error, any()}, - payable = undefined :: undefined | false | true, - main = undefined :: undefined | false | true, - contract = undefined :: undefined | tk(), - con = undefined :: undefined | tk(), - ':' = undefined :: undefined | false | {':', [tk()]} - '=' = undefined :: undefined | tk()}). +-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 @@ -38,21 +39,23 @@ main() -> %% @doc %% This is all the stuff that has to be parsed before actual parsing %% can begin. --type stem_meta() :: contract_meta(). +-type stem_meta() :: none + | contract_meta(). % @doc ys = syntax stem --record(ys, {ok = ok :: ok | {error, any()}, - target = signal :: syntax_target(), - signal = undefined :: undefined | [tk()], - stem_meta = undefined :: undefined | any(), - forest = undefined :: undefined | [#ys{}]}). +-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) -> - {ok, Sig} = gsc:unsafe_signal_from_string(SrcStr), - gulp(file, Sig); + Sig = gsc:unsafe_signal_from_string(SrcStr), + Result = gulp(file, Sig), + io:format("~tp~n", [Result]). gulp(file, Sig) -> @@ -62,7 +65,7 @@ gulp({block_of, X}, Sig) -> #ys{target = {block_of, X}, signal = Sig, stem_meta = none, - forest = [gulp(X, Item) | Item <- BlockItems]}; + forest = [gulp(X, Item) || Item <- BlockItems]}; gulp(top_decl, Sig) -> % TopDecl ::= ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl) % | 'contract' 'interface' Con [Implement] '=' Block(Decl) @@ -81,14 +84,18 @@ gulp(top_decl, Sig) -> ["payable", "contract", _] -> contract; ["contract", "interface", _] -> interface; ["contract", _, _] -> contract; - ["main", "contract", _] -> contract - ["main", "payable", "contract"] -> contract - end + ["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]; + Forest = [gulp(decl, Item) || Item <- BlockItems], + #ys{target = contract, + signal = Sig, + stem_meta = CtMeta, + forest = Forest}; gulp(NyiTarget, Sig) -> #ys{target = NyiTarget, signal = Sig, @@ -97,5 +104,74 @@ gulp(NyiTarget, Sig) -> %% ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl) -slurp(M = #ct{payable = undefined}, [#tk{str = "payable"} | Rest]) -> - slurp(M#ct{payable = true}, Rest) -> +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(_, []) -> [].