wip restructuring
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
-module(gsc_test_ntree).
|
||||
|
||||
-export([
|
||||
main/0
|
||||
]).
|
||||
|
||||
-include("$gsc_include/gsc.hrl").
|
||||
|
||||
% just parsing type expressions right now, so only need
|
||||
% to worry about round parens
|
||||
%
|
||||
% none is to indicate general-purpose grouping, for
|
||||
% e.g. LHS/RHS of an op
|
||||
-type syntax_meta()
|
||||
:: {op, tk()}
|
||||
| op_arg
|
||||
| {parens, Open :: tk(), Close :: tk()}
|
||||
.
|
||||
|
||||
-type ast() :: ntree(syntax_meta(), tk()).
|
||||
-type asf() :: nforest(syntax_meta(), tk()).
|
||||
-type asts() :: asf().
|
||||
|
||||
|
||||
main() ->
|
||||
x00(),
|
||||
ok.
|
||||
|
||||
% x00 = example00
|
||||
x00() ->
|
||||
io:format("Example 00:~n", []),
|
||||
io:format(" SrcStr = ~p~n", [x00_src()]),
|
||||
io:format(" Tokens = ~p~n", [x00_tks()]),
|
||||
io:format(" Signal = ~p~n", [x00_sgl()]),
|
||||
io:format(" Forest = ~p~n", [x00_fst()]),
|
||||
ok.
|
||||
|
||||
% sample type expr, tokens, signal
|
||||
x00_src() -> "(foo => (bar) * baz)".
|
||||
x00_tks() -> gsc:unsafe_tokens_from_string(x00_src()).
|
||||
x00_sgl() -> gsc:filter_signal(x00_tks()).
|
||||
x00_fst() -> parse(x00_sgl()).
|
||||
|
||||
|
||||
-spec parse(Signal) -> ASF when
|
||||
Signal :: [tk()],
|
||||
ASF :: asf().
|
||||
|
||||
parse(Signal) ->
|
||||
% key insight here is our signal is already a
|
||||
% forest, assuming the leaf type is `tk()`.
|
||||
%
|
||||
% our parser is a sequence of forest-to-forest
|
||||
% transformers.
|
||||
%
|
||||
% at the end we should end up with just one tree (i
|
||||
% think)?
|
||||
F0 = Signal,
|
||||
F1 = f2f_parens(F0),
|
||||
F2 = f2f_op("=>", F1),
|
||||
F3 = f2f_op("*", F2),
|
||||
Result = F2,
|
||||
Result.
|
||||
|
||||
|
||||
f2f_op(OpStr, Fst) ->
|
||||
f2f_op(OpStr, [], Fst).
|
||||
|
||||
|
||||
% never saw the op
|
||||
f2f_op(_opstr, Stk, []) ->
|
||||
lists:reverse(Stk);
|
||||
% see op
|
||||
f2f_op(OpStr, LhsStk, [#tk{str = OpStr} = OpTk | Rest]) ->
|
||||
Lhf = lists:reverse(LhsStk),
|
||||
Rhf = f2f_op(OpStr, Rest),
|
||||
Lht = #ns{meta = op_arg, kids = Lhf},
|
||||
Rht = #ns{meta = op_arg, kids = Rhf},
|
||||
ResultT = #ns{meta = {op, OpTk},
|
||||
kids = [Lht, Rht]},
|
||||
ResultF = [ResultT],
|
||||
ResultF;
|
||||
% see stem, descend
|
||||
f2f_op(OpStr, LhsStk, [Ns = #ns{kids = NsKids} | Rest]) ->
|
||||
NewNsKids = f2f_op(OpStr, NsKids),
|
||||
NewNs = Ns#ns{kids = NewNsKids},
|
||||
NewStk = [NewNs | LhsStk],
|
||||
f2f_op(OpStr, NewStk, Rest);
|
||||
% see leaf, just add
|
||||
f2f_op(OpStr, Stk, [L | Rest]) ->
|
||||
f2f_op(OpStr, [L | Stk], Rest).
|
||||
|
||||
|
||||
-spec f2f_parens(Forest) -> NewForest when
|
||||
Forest :: asts(),
|
||||
NewForest :: Forest.
|
||||
% @doc
|
||||
% recursive parens decomposition
|
||||
%
|
||||
% the input here is the flat list of tokens. here we
|
||||
% basically replace the string of tokens between `(`
|
||||
% and `)` with a single tree
|
||||
%
|
||||
% interesting quirk is that this doesn't error on too
|
||||
% many close parens, only too many open parens
|
||||
|
||||
f2f_parens(Fst) ->
|
||||
f2f_parens([], Fst).
|
||||
|
||||
% done
|
||||
f2f_parens(Stk, []) ->
|
||||
lists:reverse(Stk);
|
||||
% crawl down the forest and scan for open parens
|
||||
% open paren, we descend
|
||||
f2f_parens(Stk, [#tk{str = "("} = TkOpen | Rest0]) ->
|
||||
InitMeta = {parens, TkOpen, none},
|
||||
{slurp, PStem, Rest1} = slurp_pstem(InitMeta, [], Rest0),
|
||||
NewStk = [PStem | Stk],
|
||||
f2f_parens(NewStk, Rest1);
|
||||
% something else, we continue
|
||||
f2f_parens(Stk, [Tree | Rest]) ->
|
||||
f2f_parens([Tree | Stk], Rest).
|
||||
|
||||
|
||||
|
||||
% ran out of tokens before close paren
|
||||
slurp_pstem({parens, TkOpen, none}, Stk, []) ->
|
||||
error({no_close_for, TkOpen, Stk});
|
||||
% hit close paren, we done
|
||||
slurp_pstem({parens, TkOpen, none}, Stk, [TkClose = #tk{str = ")"} | Rest]) ->
|
||||
FinalMeta = {parens, TkOpen, TkClose},
|
||||
Midsection = lists:reverse(Stk),
|
||||
FinalTree = #ns{meta = FinalMeta,
|
||||
kids = Midsection},
|
||||
{slurp, FinalTree, Rest};
|
||||
% hit open paren, we recurse
|
||||
slurp_pstem(AccMeta, Stk, [TkOpen_II = #tk{str = "("} | Rest0]) ->
|
||||
InitMeta_II = {parens, TkOpen_II, none},
|
||||
{slurp, PStem_II, Rest1} = slurp_pstem(InitMeta_II, [], Rest0),
|
||||
NewStk = [PStem_II | Stk],
|
||||
slurp_pstem(AccMeta, NewStk, Rest1);
|
||||
% hit something else, we move along
|
||||
slurp_pstem(AccMeta, Stk, [Tree | Rest]) ->
|
||||
slurp_pstem(AccMeta, [Tree | Stk], Rest).
|
||||
Reference in New Issue
Block a user