Skip to content

Commit c11c4de

Browse files
committed
Implement support for fractional precedence
1 parent 1466261 commit c11c4de

File tree

11 files changed

+92
-10
lines changed

11 files changed

+92
-10
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
* Format multiple files in parallel. [Issue
44
1128](https://github.com/tweag/ormolu/issues/1128).
5+
* Fractional precedences are now allowed in `.ormolu` files for more precise
6+
control over formatting of complex operator chains. [Issue
7+
1106](https://github.com/tweag/ormolu/issues/1106).
58

69
* Correctly format type applications of `QuasiQuotes`. [Issue
710
1134](https://github.com/tweag/ormolu/issues/1134).

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,16 @@ infixl 1 >>, >>=
184184
infixr 1 =<<
185185
infixr 0 $, $!
186186
infixl 4 <*>, <*, *>, <**>
187+
188+
infixr 3 >~<
189+
infixr 3.3 |~|
190+
infixr 3.7 <~>
187191
```
188192

189193
It uses exactly the same syntax as usual Haskell fixity declarations to make
190-
it easier for Haskellers to edit and maintain.
194+
it easier for Haskellers to edit and maintain. Since Ormolu 0.7.8.0
195+
fractional precedences are supported for more precise control over
196+
formatting of complex operator chains.
191197

192198
As of Ormolu 0.7.0.0, `.ormolu` files can also contain instructions about
193199
module re-exports that Ormolu should be aware of. This might be desirable
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
startFormTok |~| messageTag
2+
>~< startMessageTok |~| name
3+
>~< p' |~| endMessageTok |~| endFormTok
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
startFormTok |~| messageTag
2+
>~< startMessageTok |~| name
3+
>~< p' |~| endMessageTok |~| endFormTok

extract-hackage-info/hackage-info.bin

12.8 KB
Binary file not shown.

src/Ormolu/Fixity/Internal.hs

+30-5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ where
3232

3333
import Control.DeepSeq (NFData)
3434
import Data.Binary (Binary)
35+
import Data.Binary qualified as Binary
36+
import Data.Binary.Get qualified as Binary
37+
import Data.Binary.Put qualified as Binary
3538
import Data.ByteString.Short (ShortByteString)
3639
import Data.ByteString.Short qualified as SBS
3740
import Data.Choice (Choice)
@@ -96,10 +99,20 @@ data FixityInfo = FixityInfo
9699
{ -- | Fixity direction
97100
fiDirection :: FixityDirection,
98101
-- | Precedence
99-
fiPrecedence :: Int
102+
fiPrecedence :: Double
100103
}
101104
deriving stock (Eq, Ord, Show, Generic)
102-
deriving anyclass (Binary, NFData)
105+
deriving anyclass (NFData)
106+
107+
instance Binary FixityInfo where
108+
put FixityInfo {..} = do
109+
Binary.put fiDirection
110+
Binary.putDoublele fiPrecedence
111+
112+
get = do
113+
fiDirection <- Binary.get
114+
fiPrecedence <- Binary.getDoublele
115+
pure FixityInfo {..}
103116

104117
-- | Fixity info of the built-in colon data constructor.
105118
colonFixityInfo :: FixityInfo
@@ -116,13 +129,25 @@ data FixityApproximation = FixityApproximation
116129
faDirection :: Maybe FixityDirection,
117130
-- | Minimum precedence level found in the (maybe conflicting)
118131
-- definitions for the operator (inclusive)
119-
faMinPrecedence :: Int,
132+
faMinPrecedence :: Double,
120133
-- | Maximum precedence level found in the (maybe conflicting)
121134
-- definitions for the operator (inclusive)
122-
faMaxPrecedence :: Int
135+
faMaxPrecedence :: Double
123136
}
124137
deriving stock (Eq, Ord, Show, Generic)
125-
deriving anyclass (Binary, NFData)
138+
deriving anyclass (NFData)
139+
140+
instance Binary FixityApproximation where
141+
put FixityApproximation {..} = do
142+
Binary.put faDirection
143+
Binary.putDoublele faMinPrecedence
144+
Binary.putDoublele faMaxPrecedence
145+
146+
get = do
147+
faDirection <- Binary.get
148+
faMinPrecedence <- Binary.getDoublele
149+
faMaxPrecedence <- Binary.getDoublele
150+
pure FixityApproximation {..}
126151

127152
-- | Gives the ability to merge two (maybe conflicting) definitions for an
128153
-- operator, keeping the higher level of compatible information from both.

src/Ormolu/Fixity/Parser.hs

+3-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ pFixity = do
103103
fiDirection <- pFixityDirection
104104
hidden hspace1
105105
offsetAtPrecedence <- getOffset
106-
fiPrecedence <- L.decimal
106+
fiPrecedence <-
107+
try L.float
108+
<|> (fromIntegral <$> (L.decimal :: Parser Integer))
107109
when (fiPrecedence > 9) $
108110
region
109111
(setErrorOffset offsetAtPrecedence)

src/Ormolu/Fixity/Printer.hs

+11-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import Data.Text.Lazy qualified as TL
1919
import Data.Text.Lazy.Builder (Builder)
2020
import Data.Text.Lazy.Builder qualified as B
2121
import Data.Text.Lazy.Builder.Int qualified as B
22+
import Data.Text.Lazy.Builder.RealFloat qualified as B
2223
import Distribution.ModuleName (ModuleName)
2324
import Distribution.ModuleName qualified as ModuleName
2425
import Distribution.Types.PackageName
@@ -44,7 +45,7 @@ renderSingleFixityOverride (OpName operator, FixityInfo {..}) =
4445
InfixR -> "infixr"
4546
InfixN -> "infix",
4647
" ",
47-
B.decimal fiPrecedence,
48+
renderPrecedence fiPrecedence,
4849
" ",
4950
if isTickedOperator operator
5051
then "`" <> B.fromText operator <> "`"
@@ -75,3 +76,12 @@ renderSingleModuleReexport (exportingModule, exports) =
7576

7677
renderModuleName :: ModuleName -> Builder
7778
renderModuleName = B.fromString . intercalate "." . ModuleName.components
79+
80+
-- | Render precedence using integer representation for whole numbers.
81+
renderPrecedence :: Double -> Builder
82+
renderPrecedence x =
83+
let (n :: Int, fraction :: Double) = properFraction x
84+
isWholeEnough = fraction < 0.0001
85+
in if isWholeEnough
86+
then B.decimal n
87+
else B.realFloat x

tests/Ormolu/Fixity/ParserSpec.hs

+22
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ spec = do
3535
`shouldParse` ( exampleFixityOverrides,
3636
ModuleReexports Map.empty
3737
)
38+
it "accepts fractional operator precedences" $
39+
parseDotOrmolu
40+
""
41+
( T.unlines
42+
[ "infixr 3 >~<",
43+
"infixr 3.3 |~|",
44+
"infixr 3.7 <~>"
45+
]
46+
)
47+
`shouldParse` ( fractionalFixityOverrides,
48+
ModuleReexports Map.empty
49+
)
3850
it "combines conflicting fixity declarations correctly" $
3951
parseDotOrmolu
4052
""
@@ -231,6 +243,16 @@ exampleFixityOverrides =
231243
]
232244
)
233245

246+
fractionalFixityOverrides :: FixityOverrides
247+
fractionalFixityOverrides =
248+
FixityOverrides
249+
( Map.fromList
250+
[ (">~<", FixityInfo InfixR 3),
251+
("|~|", FixityInfo InfixR 3.3),
252+
("<~>", FixityInfo InfixR 3.7)
253+
]
254+
)
255+
234256
exampleModuleReexports :: ModuleReexports
235257
exampleModuleReexports =
236258
ModuleReexports . Map.fromList $

tests/Ormolu/Fixity/PrinterSpec.hs

+6-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ instance Arbitrary FixityOverrides where
3737
InfixR,
3838
InfixN
3939
]
40-
fiPrecedence <- chooseInt (0, 9)
40+
precedenceWholePart <- fromIntegral <$> chooseInt (0, 9)
41+
precedenceFractionalPart <-
42+
if precedenceWholePart < 9.0
43+
then (* 0.1) . fromIntegral <$> chooseInt (0, 1)
44+
else return 0
45+
let fiPrecedence = precedenceWholePart + precedenceFractionalPart
4146
return FixityInfo {..}
4247

4348
instance Arbitrary ModuleReexports where

tests/Ormolu/PrinterSpec.hs

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ testsuiteOverrides =
3131
FixityOverrides
3232
( Map.fromList
3333
[ (".=", FixityInfo InfixR 8),
34-
("#", FixityInfo InfixR 5)
34+
("#", FixityInfo InfixR 5),
35+
(">~<", FixityInfo InfixR 3),
36+
("|~|", FixityInfo InfixR 3.3),
37+
("<~>", FixityInfo InfixR 3.7)
3538
]
3639
)
3740

0 commit comments

Comments
 (0)