
Okay, I believe I have come up with a modified version that accepts many more programs and doesn't require complicated comma handling, you can make all decisions based on the top of the context stack. It also allows many useful layouts that were illegal under the old system. The main change was to store the expected closing token in addition to the opening one on the context stack, then look up the appropriate token in a table based on the immediately enclosing context. Unlike the old version that recursed up the stack, this only needs to look at the top. The rules are (where _ means true everywhere) always enabled: (case,of) (if,then) (then,else) ('(',')') ('[',']') ('{','}') conditional: of => ('|','->') let => ('|','=') '[' => ('|',']') then we follow the same rules as before, except we check the token against the stored ending token at the top of the stack and 'let' is only terminated by ',' if '|' is at the top of the context stack. In addition I added a list of 'layout insensitive' symbols, that will never poke the layout rule, they are ["|","->","=",";",","]. lines starting with these will not continue or close layout contexts. So, there are still a couple obscure cases this won't lay out properly, but it does allow some handy things that were not allowed before. it boils down to the fact that layout is turned off inside any enclosing brackets and effects do not propagate outside of them. So nothing done between [ .. ] can affect anything outside of them. some handy things this allows -- a 'cond' construct that lines up nicely. foo = case () of () | cond1 -> exp1 | cond2 -> exp2 | cond3 -> exp3 line up your tuple defs (alpha ,beta ,gamma) = foo no need to double indent conditionals in do let let f x y z | x == z = y | x == y = z | y == z = x The simple rule is, inside enclosing brackets, layout is turned off and doesn't propagate. I am testing the rules with ghc and they are promising so far. pattern bindings John