.
aliases . get_files => make_notes => make_blocks => make_lines
--amend
get body by one of many heads
Tree

generic Tree with:
tree.map()
tree.filter()
tree.fold()

implement "tree to edges" as memoized fold:
the input is the edge
the output is input to the next edge

the AST left associates the n-ary CST into binary Tree,
moving the verb from the children to the value.

config dicts with __default__ key become defaultdicts

flatten as multimethod

parse.head() calls parse._head(), which returns each interesting transform:
CST
AST
Graph

test with:
$ ./main.py --parse 'x , y , z : a = b := c'
Edges!

`parse.head` returns every stage of parse flow
`parse.head` = associate => left associate => strip infix => make edges => get verbs
`Parsed` : head, line, cst, ast, nodes, edges, verbs

`left_associate` only left associates binary operators. thus, each `Op` `value` in the `Tree` has only one symbol.

parse skips unary operators
e.g. '+ ACh' => ['', '+', 'ACh'] => ['+', 'ACh'] => '+ ACh'

`Op.strip` uses __class__ to repack -> method works with any child class
`Op.__repr__` with %r
`Op.symbol` : str = same string as config operator
`Binop.__init__(*symbols)` is now n-ary function

`Tree.filter(... g=)` can filter on `trees` now (not just `value`)

doctests

map operators (e.g. '->') to verbs (e.g. 'causes')

reducers take an operator as well as the words they are reducing
e.g. left(',', ['x', 'y']) = 'x'
e.g. join('+', ['x', 'y']) = 'x + y'

test:
$ ./main -t
Narop an n-ary operator.
like binary, is chainable.
unlike binary, it is not left-associated, so the 2+ operands are all passed to the verb.
e.g. syntax: [".", "."] in config
e.g. semantics: 'x . y . z' => ('and', 'x', 'y', 'z')

`raise PatternExhausted`