
-spec s2t_file(Signal) -> AstFile when
        Signal  :: [tk()],
        AstFile :: #ns{meta :: file, kids :: asf()}.

s2t_file([]) ->
    error(empty_file);
s2t_file(S0 = [#tk{pos = {_, FileCol}} | _]) ->
    Blk0 = s2t_gulp_block(FileCol, S0),
    Blk1 = t2t_parse_tds_in_block(Blk0),
    #ns{meta = file, kids = [Blk1]}.

-spec s2t_gulp_block(BlkCol, Signal) -> Block when
        BlkCol :: pos_integer(),
        Signal :: [tk()],
        Block  :: #ns{meta :: block}.

s2t_gulp_block(BCol, Tks) ->
    % sanity check
    InBlock = fun(#tk{pos = {_, TCol}}) -> BCol =< TCol end,
    true = lists:all(InBlock, Tks),
    BlockItems = s2f_block_items(BCol, Tks),
    #ns{meta = block, kids = BlockItems}.

-spec s2f_block_items(BCol, Signal) -> BlkItems when
        BCol :: pos_integer(),
        Signal :: [tk()],
        BlkItems :: [BlkItem],
        BlkItem :: #ns{meta :: block_item,
                       kids :: asf()}.

s2f_block_items(BCol, Signal) ->
    s2f_block_items(BCol, [], Signal).


s2f_block_items(_BCol, Stk, []) ->
    lists:reverse(Stk);
s2f_block_items(BCol, Stk, [#tk{pos = {_, BCol}} = T0 | F0]) ->
    {slurp, BlkItem, F1} = s2t_slurp_block_item(BCol, T0, F0),
    s2f_block_items(BCol, [BlkItem | Stk], F1).


s2t_slurp_block_item(BCol, T0, F0) ->
    {ItemTokens, F1} = s2s_sw_block_item(BCol, T0, F0),
    Item = #ns{meta = block_item, kids = ItemTokens},
    {slurp, Item, F1}.

% sw = splitwith; kind of take/drop
s2s_sw_block_item(BCol, T0, F0) ->
    InItem = fun(#tk{pos = {_, TCol}}) -> BCol < TCol end,
    {F0_II, F1} = lists:splitwith(InItem, F0),
    {[T0 | F0_II], F1}.

-spec t2t_parse_tds_in_block(Block0) -> Block1 when
        Block0 :: ast(),
        Block1 :: ast().

% go through and convert the block_item nodes to top
% decls
t2t_parse_tds_in_block(B0 = #ns{meta = block, kids = F0}) ->
    F1 = lists:map(fun t2t_parse_td_from_item/1, F0),
    B0#ns{kids = F1}.


-spec t2t_parse_td_from_item(BlockItem) -> TopDecl when
        BlockItem :: #ns{meta :: block_item},
        TopDecl   :: #ns{meta :: td_meta()}.

t2t_parse_td_from_item(#ns{meta = block_item, kids = Signal}) ->
    s2t_top_decl(Signal).


-spec s2t_top_decl(Signal) -> TdTree when
        Signal :: [tk()],
        TdTree :: ast().

s2t_top_decl(S0) ->
