-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) ->