Skip to content

Commit 4a8f16f

Browse files
authored
Merge pull request #382 from haskell/mpj/uint31
Replace Word32 with a newtype
2 parents 6804c53 + b48cf78 commit 4a8f16f

File tree

16 files changed

+107
-73
lines changed

16 files changed

+107
-73
lines changed

lsp-types/lsp-types.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ library
8686
, lens >= 4.15.2
8787
, mtl
8888
, network-uri
89+
, mod
8990
, rope-utf16-splay >= 0.3.1.0
9091
, scientific
9192
, some

lsp-types/src/Language/LSP/Types/Common.hs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+
{-# LANGUAGE DataKinds #-}
3+
{-# LANGUAGE DeriveAnyClass #-}
24
{-# LANGUAGE DeriveTraversable #-}
35
{-# LANGUAGE DeriveGeneric #-}
6+
{-# LANGUAGE DerivingStrategies #-}
47
{-# LANGUAGE TypeOperators #-}
58

69
-- | Common types that aren't in the specification
@@ -10,14 +13,44 @@ module Language.LSP.Types.Common (
1013
, List (..)
1114
, Empty (..)
1215
, Int32
13-
, Word32 ) where
16+
, UInt ) where
1417

1518
import Control.Applicative
1619
import Control.DeepSeq
1720
import Data.Aeson
1821
import Data.Int (Int32)
19-
import Data.Word (Word32)
20-
import GHC.Generics
22+
import Data.Mod.Word
23+
import Text.Read (Read(readPrec))
24+
import GHC.Generics hiding (UInt)
25+
import GHC.TypeNats hiding (Mod)
26+
import Data.Bifunctor (bimap)
27+
28+
-- | The "uinteger" type in the LSP spec.
29+
--
30+
-- Unusually, this is a **31**-bit unsigned integer, not a 32-bit one.
31+
newtype UInt = UInt (Mod (2^31))
32+
deriving newtype (Num, Bounded, Enum, Eq, Ord)
33+
deriving stock (Generic)
34+
deriving anyclass (NFData)
35+
36+
instance Show UInt where
37+
show (UInt u) = show $ unMod u
38+
39+
instance Read UInt where
40+
readPrec = fromInteger <$> readPrec
41+
42+
instance Real UInt where
43+
toRational (UInt u) = toRational $ unMod u
44+
45+
instance Integral UInt where
46+
quotRem (UInt x) (UInt y) = bimap fromIntegral fromIntegral $ quotRem (unMod x) (unMod y)
47+
toInteger (UInt u) = toInteger $ unMod u
48+
49+
instance ToJSON UInt where
50+
toJSON u = toJSON (toInteger u)
51+
52+
instance FromJSON UInt where
53+
parseJSON v = fromInteger <$> parseJSON v
2154

2255
-- | A terser, isomorphic data type for 'Either', that does not get tagged when
2356
-- converting to and from JSON.
@@ -46,7 +79,8 @@ instance (NFData a, NFData b) => NFData (a |? b)
4679
-- In particular this is necessary to change the 'FromJSON' instance to be compatible
4780
-- with Elisp (where empty lists show up as 'null')
4881
newtype List a = List [a]
49-
deriving (Show,Read,Eq,Ord,Semigroup,Monoid,Functor,Foldable,Traversable,Generic)
82+
deriving stock (Traversable,Generic)
83+
deriving newtype (Show,Read,Eq,Ord,Semigroup,Monoid,Functor,Foldable)
5084

5185
instance NFData a => NFData (List a)
5286

lsp-types/src/Language/LSP/Types/Diagnostic.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Control.DeepSeq
99
import qualified Data.Aeson as A
1010
import Data.Aeson.TH
1111
import Data.Text
12-
import GHC.Generics
12+
import GHC.Generics hiding (UInt)
1313
import Language.LSP.Types.Common
1414
import Language.LSP.Types.Location
1515
import Language.LSP.Types.Uri
@@ -131,7 +131,7 @@ data PublishDiagnosticsParams =
131131
-- published for.
132132
--
133133
-- Since LSP 3.15.0
134-
, _version :: Maybe Word32
134+
, _version :: Maybe UInt
135135
-- | An array of diagnostic information items.
136136
, _diagnostics :: List Diagnostic
137137
} deriving (Read,Show,Eq)

lsp-types/src/Language/LSP/Types/FoldingRange.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ data FoldingRangeClientCapabilities =
2424
_dynamicRegistration :: Maybe Bool
2525
-- | The maximum number of folding ranges that the client prefers to receive
2626
-- per document. The value serves as a hint, servers are free to follow the limit.
27-
, _rangeLimit :: Maybe Word32
27+
, _rangeLimit :: Maybe UInt
2828
-- | If set, the client signals that it only supports folding complete lines. If set,
2929
-- client will ignore specified `startCharacter` and `endCharacter` properties in a
3030
-- FoldingRange.
@@ -80,15 +80,15 @@ instance A.FromJSON FoldingRangeKind where
8080
data FoldingRange =
8181
FoldingRange
8282
{ -- | The zero-based line number from where the folded range starts.
83-
_startLine :: Word32
83+
_startLine :: UInt
8484
-- | The zero-based character offset from where the folded range
8585
-- starts. If not defined, defaults to the length of the start line.
86-
, _startCharacter :: Maybe Word32
86+
, _startCharacter :: Maybe UInt
8787
-- | The zero-based line number where the folded range ends.
88-
, _endLine :: Word32
88+
, _endLine :: UInt
8989
-- | The zero-based character offset before the folded range ends.
9090
-- If not defined, defaults to the length of the end line.
91-
, _endCharacter :: Maybe Word32
91+
, _endCharacter :: Maybe UInt
9292
-- | Describes the kind of the folding range such as 'comment' or
9393
-- 'region'. The kind is used to categorize folding ranges and used
9494
-- by commands like 'Fold all comments'. See 'FoldingRangeKind' for

lsp-types/src/Language/LSP/Types/Formatting.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ deriveJSON lspOptions ''DocumentFormattingRegistrationOptions
3030
-- | Value-object describing what options formatting should use.
3131
data FormattingOptions = FormattingOptions
3232
{ -- | Size of a tab in spaces.
33-
_tabSize :: Word32,
33+
_tabSize :: UInt,
3434
-- | Prefer spaces over tabs
3535
_insertSpaces :: Bool,
3636
-- | Trim trailing whitespace on a line.

lsp-types/src/Language/LSP/Types/Location.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ import Language.LSP.Types.Utils
1414
data Position =
1515
Position
1616
{ -- | Line position in a document (zero-based).
17-
_line :: Word32
17+
_line :: UInt
1818
-- | Character offset on a line in a document (zero-based). Assuming that
1919
-- the line is represented as a string, the @character@ value represents the
2020
-- gap between the @character@ and @character + 1@.
21-
, _character :: Word32
21+
, _character :: UInt
2222
} deriving (Show, Read, Eq, Ord, Generic)
2323

2424
instance NFData Position
@@ -73,5 +73,5 @@ deriveJSON lspOptions ''LocationLink
7373

7474
-- | A helper function for creating ranges.
7575
-- prop> mkRange l c l' c' = Range (Position l c) (Position l' c')
76-
mkRange :: Word32 -> Word32 -> Word32 -> Word32 -> Range
76+
mkRange :: UInt -> UInt -> UInt -> UInt -> Range
7777
mkRange l c l' c' = Range (Position l c) (Position l' c')

lsp-types/src/Language/LSP/Types/Progress.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ data WorkDoneProgressBeginParams =
5959
--
6060
-- The value should be steadily rising. Clients are free to ignore values
6161
-- that are not following this rule.
62-
, _percentage :: Maybe Word32
62+
, _percentage :: Maybe UInt
6363
} deriving (Show, Read, Eq)
6464

6565
instance A.ToJSON WorkDoneProgressBeginParams where
@@ -104,7 +104,7 @@ data WorkDoneProgressReportParams =
104104
-- If infinite progress was indicated in the start notification client
105105
-- are allowed to ignore the value. In addition the value should be steadily
106106
-- rising. Clients are free to ignore values that are not following this rule.
107-
, _percentage :: Maybe Word32
107+
, _percentage :: Maybe UInt
108108
} deriving (Show, Read, Eq)
109109

110110
instance A.ToJSON WorkDoneProgressReportParams where

lsp-types/src/Language/LSP/Types/SemanticTokens.hs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,12 @@ data SemanticTokens = SemanticTokens {
292292
_resultId :: Maybe Text,
293293

294294
-- | The actual tokens.
295-
_xdata :: List Word32
295+
_xdata :: List UInt
296296
} deriving (Show, Read, Eq)
297297
deriveJSON lspOptions ''SemanticTokens
298298

299299
data SemanticTokensPartialResult = SemanticTokensPartialResult {
300-
_xdata :: List Word32
300+
_xdata :: List UInt
301301
}
302302
deriveJSON lspOptions ''SemanticTokensPartialResult
303303

@@ -311,11 +311,11 @@ deriveJSON lspOptions ''SemanticTokensDeltaParams
311311

312312
data SemanticTokensEdit = SemanticTokensEdit {
313313
-- | The start offset of the edit.
314-
_start :: Word32,
314+
_start :: UInt,
315315
-- | The count of elements to remove.
316-
_deleteCount :: Word32,
316+
_deleteCount :: UInt,
317317
-- | The elements to insert.
318-
_xdata :: Maybe (List Word32)
318+
_xdata :: Maybe (List UInt)
319319
} deriving (Show, Read, Eq)
320320
deriveJSON lspOptions ''SemanticTokensEdit
321321

@@ -359,9 +359,9 @@ deriveJSON lspOptions ''SemanticTokensWorkspaceClientCapabilities
359359
-- | A single 'semantic token' as described in the LSP specification, using absolute positions.
360360
-- This is the kind of token that is usually easiest for editors to produce.
361361
data SemanticTokenAbsolute = SemanticTokenAbsolute {
362-
line :: Word32,
363-
startChar :: Word32,
364-
length :: Word32,
362+
line :: UInt,
363+
startChar :: UInt,
364+
length :: UInt,
365365
tokenType :: SemanticTokenTypes,
366366
tokenModifiers :: [SemanticTokenModifiers]
367367
} deriving (Show, Read, Eq, Ord)
@@ -370,9 +370,9 @@ data SemanticTokenAbsolute = SemanticTokenAbsolute {
370370

371371
-- | A single 'semantic token' as described in the LSP specification, using relative positions.
372372
data SemanticTokenRelative = SemanticTokenRelative {
373-
deltaLine :: Word32,
374-
deltaStartChar :: Word32,
375-
length :: Word32,
373+
deltaLine :: UInt,
374+
deltaStartChar :: UInt,
375+
length :: UInt,
376376
tokenType :: SemanticTokenTypes,
377377
tokenModifiers :: [SemanticTokenModifiers]
378378
} deriving (Show, Read, Eq, Ord)
@@ -385,7 +385,7 @@ relativizeTokens :: [SemanticTokenAbsolute] -> [SemanticTokenRelative]
385385
relativizeTokens xs = DList.toList $ go 0 0 xs mempty
386386
where
387387
-- Pass an accumulator to make this tail-recursive
388-
go :: Word32 -> Word32 -> [SemanticTokenAbsolute] -> DList.DList SemanticTokenRelative -> DList.DList SemanticTokenRelative
388+
go :: UInt -> UInt -> [SemanticTokenAbsolute] -> DList.DList SemanticTokenRelative -> DList.DList SemanticTokenRelative
389389
go _ _ [] acc = acc
390390
go lastLine lastChar (SemanticTokenAbsolute l c len ty mods:ts) acc =
391391
let
@@ -400,7 +400,7 @@ absolutizeTokens :: [SemanticTokenRelative] -> [SemanticTokenAbsolute]
400400
absolutizeTokens xs = DList.toList $ go 0 0 xs mempty
401401
where
402402
-- Pass an accumulator to make this tail-recursive
403-
go :: Word32 -> Word32 -> [SemanticTokenRelative] -> DList.DList SemanticTokenAbsolute -> DList.DList SemanticTokenAbsolute
403+
go :: UInt -> UInt -> [SemanticTokenRelative] -> DList.DList SemanticTokenAbsolute -> DList.DList SemanticTokenAbsolute
404404
go _ _ [] acc = acc
405405
go lastLine lastChar (SemanticTokenRelative dl dc len ty mods:ts) acc =
406406
let
@@ -410,18 +410,18 @@ absolutizeTokens xs = DList.toList $ go 0 0 xs mempty
410410
in go l c ts (DList.snoc acc (SemanticTokenAbsolute l c len ty mods))
411411

412412
-- | Encode a series of relatively-positioned semantic tokens into an integer array following the given legend.
413-
encodeTokens :: SemanticTokensLegend -> [SemanticTokenRelative] -> Either Text [Word32]
413+
encodeTokens :: SemanticTokensLegend -> [SemanticTokenRelative] -> Either Text [UInt]
414414
encodeTokens SemanticTokensLegend{_tokenTypes=List tts,_tokenModifiers=List tms} sts =
415415
DList.toList . DList.concat <$> traverse encodeToken sts
416416
where
417417
-- Note that there's no "fast" version of these (e.g. backed by an IntMap or similar)
418418
-- in general, due to the possibility of unknown token types which are only identified by strings.
419-
tyMap :: Map.Map SemanticTokenTypes Word32
419+
tyMap :: Map.Map SemanticTokenTypes UInt
420420
tyMap = Map.fromList $ zip tts [0..]
421421
modMap :: Map.Map SemanticTokenModifiers Int
422422
modMap = Map.fromList $ zip tms [0..]
423423

424-
lookupTy :: SemanticTokenTypes -> Either Text Word32
424+
lookupTy :: SemanticTokenTypes -> Either Text UInt
425425
lookupTy ty = case Map.lookup ty tyMap of
426426
Just tycode -> pure tycode
427427
Nothing -> throwError $ "Semantic token type " <> fromString (show ty) <> " did not appear in the legend"
@@ -431,17 +431,17 @@ encodeTokens SemanticTokensLegend{_tokenTypes=List tts,_tokenModifiers=List tms}
431431
Nothing -> throwError $ "Semantic token modifier " <> fromString (show modifier) <> " did not appear in the legend"
432432

433433
-- Use a DList here for better efficiency when concatenating all these together
434-
encodeToken :: SemanticTokenRelative -> Either Text (DList.DList Word32)
434+
encodeToken :: SemanticTokenRelative -> Either Text (DList.DList UInt)
435435
encodeToken (SemanticTokenRelative dl dc len ty mods) = do
436436
tycode <- lookupTy ty
437437
modcodes <- traverse lookupMod mods
438-
let combinedModcode :: Word32 = foldl' Bits.setBit Bits.zeroBits modcodes
438+
let combinedModcode :: Int = foldl' Bits.setBit Bits.zeroBits modcodes
439439

440-
pure [dl, dc, len, tycode, combinedModcode ]
440+
pure [dl, dc, len, tycode, fromIntegral combinedModcode ]
441441

442442
-- This is basically 'SemanticTokensEdit', but slightly easier to work with.
443443
-- | An edit to a buffer of items.
444-
data Edit a = Edit { editStart :: Word32, editDeleteCount :: Word32, editInsertions :: [a] }
444+
data Edit a = Edit { editStart :: UInt, editDeleteCount :: UInt, editInsertions :: [a] }
445445
deriving (Read, Show, Eq, Ord)
446446

447447
-- | Compute a list of edits that will turn the first list into the second list.
@@ -455,7 +455,7 @@ computeEdits l r = DList.toList $ go 0 Nothing (Diff.getGroupedDiff l r) mempty
455455
dump the 'Edit' into the accumulator.
456456
We need the index, because 'Edit's need to say where they start.
457457
-}
458-
go :: Word32 -> Maybe (Edit a) -> [Diff.Diff [a]] -> DList.DList (Edit a) -> DList.DList (Edit a)
458+
go :: UInt -> Maybe (Edit a) -> [Diff.Diff [a]] -> DList.DList (Edit a) -> DList.DList (Edit a)
459459
-- No more diffs: append the current edit if there is one and return
460460
go _ e [] acc = acc <> DList.fromList (maybeToList e)
461461

lsp-types/src/Language/LSP/Types/SignatureHelp.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ deriveJSON lspOptionsUntagged ''SignatureHelpDoc
8585

8686
-- -------------------------------------
8787

88-
data ParameterLabel = ParameterLabelString Text | ParameterLabelOffset Word32 Word32
88+
data ParameterLabel = ParameterLabelString Text | ParameterLabelOffset UInt UInt
8989
deriving (Read,Show,Eq)
9090

9191
instance ToJSON ParameterLabel where
@@ -127,7 +127,7 @@ data SignatureInformation =
127127
{ _label :: Text -- ^ The label of the signature.
128128
, _documentation :: Maybe SignatureHelpDoc -- ^ The human-readable doc-comment of this signature.
129129
, _parameters :: Maybe (List ParameterInformation) -- ^ The parameters of this signature.
130-
, _activeParameter :: Maybe Word32 -- ^ The index of the active parameter.
130+
, _activeParameter :: Maybe UInt -- ^ The index of the active parameter.
131131
} deriving (Read,Show,Eq)
132132

133133
deriveJSON lspOptions ''SignatureInformation
@@ -141,8 +141,8 @@ active and only one active parameter.
141141
data SignatureHelp =
142142
SignatureHelp
143143
{ _signatures :: List SignatureInformation -- ^ One or more signatures.
144-
, _activeSignature :: Maybe Word32 -- ^ The active signature.
145-
, _activeParameter :: Maybe Word32 -- ^ The active parameter of the active signature.
144+
, _activeSignature :: Maybe UInt -- ^ The active signature.
145+
, _activeParameter :: Maybe UInt -- ^ The active parameter of the active signature.
146146
} deriving (Read,Show,Eq)
147147

148148
deriveJSON lspOptions ''SignatureHelp

lsp-types/src/Language/LSP/Types/TextDocument.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ data TextDocumentContentChangeEvent =
169169
_range :: Maybe Range
170170
-- | The optional length of the range that got replaced.
171171
-- Deprecated, use _range instead
172-
, _rangeLength :: Maybe Word32
172+
, _rangeLength :: Maybe UInt
173173
-- | The new text for the provided range, if provided.
174174
-- Otherwise the new text of the whole document.
175175
, _text :: Text

lsp-types/src/Language/LSP/Types/WorkspaceEdit.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ data ApplyWorkspaceEditResponseBody =
363363
-- might contain the index of the change that failed. This property is
364364
-- only available if the client signals a `failureHandling` strategy
365365
-- in its client capabilities.
366-
, _failedChange :: Maybe Word32
366+
, _failedChange :: Maybe UInt
367367
} deriving (Show, Read, Eq)
368368

369369
deriveJSON lspOptions ''ApplyWorkspaceEditResponseBody
@@ -388,7 +388,7 @@ applyTextEdit (TextEdit (Range sp ep) newText) oldText =
388388
in T.splitAt (fromIntegral index) t
389389

390390
-- The index of the first character of line 'line'
391-
startLineIndex :: Word32 -> Text -> Word32
391+
startLineIndex :: UInt -> Text -> UInt
392392
startLineIndex 0 _ = 0
393393
startLineIndex line t' =
394394
case T.findIndex (== '\n') t' of

lsp/example/Reactor.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ handle = mconcat
280280
responder (Right (J.Object mempty)) -- respond to the request
281281

282282
void $ withProgress "Executing some long running command" Cancellable $ \update ->
283-
forM [(0 :: J.Word32)..10] $ \i -> do
283+
forM [(0 :: J.UInt)..10] $ \i -> do
284284
update (ProgressAmount (Just (i * 10)) (Just "Doing stuff"))
285285
liftIO $ threadDelay (1 * 1000000)
286286
]

lsp/src/Language/LSP/Server/Core.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ defaultOptions = def
267267
-- an optional message to go with it during a 'withProgress'
268268
--
269269
-- @since 0.10.0.0
270-
data ProgressAmount = ProgressAmount (Maybe Word32) (Maybe Text)
270+
data ProgressAmount = ProgressAmount (Maybe UInt) (Maybe Text)
271271

272272
-- | Thrown if the user cancels a 'Cancellable' 'withProgress'/'withIndefiniteProgress'/ session
273273
--

lsp/test/JsonSpec.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ instance Arbitrary HoverContents where
9999
, HoverContents <$> arbitrary
100100
]
101101

102+
instance Arbitrary UInt where
103+
arbitrary = fromInteger <$> arbitrary
104+
102105
instance Arbitrary Uri where
103106
arbitrary = Uri <$> arbitrary
104107

0 commit comments

Comments
 (0)