on master help sign in
start using D.customString in Elm.Version
bf54eaeEvan Czaplicki
compiler/src/Elm/Version.hs+73−43
@@ -1,3 +1,5 @@
1+{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE BangPatterns, UnboxedTuples #-}
1module Elm.Version
3module Elm.Version
2 ( Version(..)
4 ( Version(..)
3 , one
5 , one
@@ -7,10 +9,11 @@ module Elm.Version
7 , bumpMinor
9 , bumpMinor
8 , bumpMajor
10 , bumpMajor
9 , toChars
11 , toChars
10− , toString
12+ --
11− , fromString
12 , decoder
13 , decoder
13 , encode
14 , encode
15+ --
16+ , parser
14 )
17 )
15 where
18 where
16
19
@@ -18,13 +21,15 @@ module Elm.Version
18import Prelude hiding (max)
21import Prelude hiding (max)
19import Control.Monad (liftM3)
22import Control.Monad (liftM3)
20import Data.Binary (Binary, get, put, getWord8, putWord8)
23import Data.Binary (Binary, get, put, getWord8, putWord8)
21−import qualified Data.Utf8 as Utf8
22import qualified Data.Version as Version
24import qualified Data.Version as Version
23−import Data.Word (Word16)
25+import Data.Word (Word8, Word16)
26+import Foreign.Ptr (Ptr, plusPtr, minusPtr)
24import qualified Paths_elm
27import qualified Paths_elm
25
28
26import qualified Json.Decode as D
29import qualified Json.Decode as D
27import qualified Json.Encode as E
30import qualified Json.Encode as E
31+import qualified Parse.Primitives as P
32+import Parse.Primitives (Row, Col)
28
33
29
34
30
35
@@ -86,58 +91,26 @@ bumpMajor (Version major _minor _patch) =
86
91
87
92
88
93
89−-- TO STRING
94+-- TO CHARS
90
95
91
96
92−toChars :: Version -> String
97+toChars :: Version -> [Char]
93−toChars vsn =
94− Utf8.toChars (toString vsn)
95−
96−
97−toString :: Version -> Utf8.String
98−toString (Version major minor patch) =
98+toChars (Version major minor patch) =
99− Utf8.join 0x2E {- . -}
99+ show major ++ '.' : show minor ++ '.' : show patch
100− [ Utf8.fromWord16 major
101− , Utf8.fromWord16 minor
102− , Utf8.fromWord16 patch
103− ]
104−
105−
106−
107−-- FROM STRING
108−
109−
110−fromString :: Utf8.String -> Maybe Version
111−fromString str =
112− case Utf8.split 0x2E {- . -} str of
113− [major, minor, patch] ->
114− Version
115− <$> Utf8.toWord16 major
116− <*> Utf8.toWord16 minor
117− <*> Utf8.toWord16 patch
118−
119− _ ->
120− Nothing
121
100
122
101
123
102
124-- JSON
103-- JSON
125
104
126
105
127−decoder :: D.Decoder Utf8.String Version
106+decoder :: D.Decoder (Row, Col) Version
128decoder =
107decoder =
129− do str <- D.string
108+ D.customString parser (,)
130− case fromString str of
131− Just version ->
132− return version
133−
134− Nothing ->
135− D.failure str
136
109
137
110
138encode :: Version -> E.Value
111encode :: Version -> E.Value
139encode version =
112encode version =
140− E.string (toString version)
113+ E.chars (toChars version)
141
114
142
115
143
116
@@ -164,3 +137,60 @@ instance Binary Version where
164 put major
137 put major
165 put minor
138 put minor
166 put patch
139 put patch
140+
141+
142+
143+-- PARSER
144+
145+
146+parser :: P.Parser (Row, Col) Version
147+parser =
148+ do major <- numberParser
149+ P.word1 0x2E {-.-} (,)
150+ minor <- numberParser
151+ P.word1 0x2E {-.-} (,)
152+ patch <- numberParser
153+ return (Version major minor patch)
154+
155+
156+numberParser :: P.Parser (Row, Col) Word16
157+numberParser =
158+ P.Parser $ \(P.State src pos end indent row col) cok _ _ eerr ->
159+ if pos >= end then
160+ eerr row col (,)
161+ else
162+ let !word = P.unsafeIndex pos in
163+ if word == 0x30 {-0-} then
164+
165+ let
166+ !newState = P.State src (plusPtr pos 1) end indent row (col + 1)
167+ in
168+ cok 0 newState
169+
170+ else if isDigit word then
171+
172+ let
173+ (# total, newPos #) = chompWord16 (plusPtr pos 1) end (fromIntegral (word - 0x30))
174+ !newState = P.State src newPos end indent row (col + fromIntegral (minusPtr newPos pos))
175+ in
176+ cok total newState
177+
178+ else
179+ eerr row col (,)
180+
181+
182+chompWord16 :: Ptr Word8 -> Ptr Word8 -> Word16 -> (# Word16, Ptr Word8 #)
183+chompWord16 pos end total =
184+ if pos >= end then
185+ (# total, pos #)
186+ else
187+ let !word = P.unsafeIndex pos in
188+ if isDigit word then
189+ chompWord16 (plusPtr pos 1) end (10 * total + fromIntegral (word - 0x30))
190+ else
191+ (# total, pos #)
192+
193+
194+isDigit :: Word8 -> Bool
195+isDigit word =
196+ 0x30 {-0-} <= word && word <= 0x39 {-9-}