tweag/ormolu

Support “fine-grained” operator precedence

sellout opened this issue · 0 comments

I sometimes end up with long chains of operators with identical precedence. E.g., in some parser code, I have

infixr 3 >~< -- run two parsers with whitespace between them
infixr 3 |~| -- run two parsers with optional whitespace between them
infixr 3 <~> -- run two parsers without whitespace between them

They should have the same precedence, because they’re mutually associative, so that’s all good. But when Ormolu formats a chain split across multiple lines, it can get noisy

startFormTok
  |~| messageTag
  >~< startMessageTok
  |~| name
  >~< p'
  |~| endMessageTok
  |~| endFormTok

What I would like is for Ormolu to treat them so that required whitespace is lower precedence than optional, is lower than illegal whitespace, so I can have it formatted like

startFormTok |~| messageTag
  >~< startMessageTok |~| name
  >~< p' |~| endMessageTok |~| endFormTok

I think a fairly clean solution would be for the .ormolu file to parse the precedences as floating point, rather than integers. Existing .ormolu files should work as is, but I can edit it to look like

infixr 3 >~<
infixr 3.3 |~|
infixr 3.7 <~>

and get the behavior I want.

As far as working with #846, perhaps regeneration could update the integral part without affecting the fractional part, so the fine-grained relationships are preserved even if the operator precedence has shifted.

What I currently do is fill my .ormolu with lies. Using incorrect precedences like

infixr 3 >~<
infixr 4 |~|
infixr 5 <~>

gets me the behavior I want, but I have to be careful to adjust any other precedences that bump into these.