1
1
{-|
2
2
Module : Language.Rust.Data.InputStream
3
3
Description : Interface to the underlying input of parsing
4
- Copyright : (c) Alec Theriault, 2017
4
+ Copyright : (c) Alec Theriault, 2017-2018
5
5
License : BSD-style
6
6
Maintainer : alec.theriault@gmail.com
7
7
Stability : experimental
8
8
Portability : portable
9
9
10
10
These are the only functions that need to be implemented in order to use the parser. Whether this
11
11
wraps 'ByteString' or 'String' depends on whether the @useByteStrings@ option is on or not (it is
12
- by default). Using 'ByteString' means better handling of weird characters ('takeByte' fails badly
13
- if you try to take a byte that doesn't fall on a character boundary), but it means incurring a
14
- dependency on the [utf8-string](https://hackage.haskell.org/package/utf8-string) package.
12
+ by default). Using 'ByteString' means better handling of weird characters ('takeByte' for plain old
13
+ 'String' fails badly if you try to take a byte that doesn't fall on a character boundary), but it
14
+ means incurring a dependency on the [utf8-string](https://hackage.haskell.org/package/utf8-string)
15
+ package.
15
16
-}
16
17
{-# LANGUAGE CPP #-}
17
18
@@ -45,50 +46,95 @@ import qualified Data.ByteString.UTF8 as BE
45
46
import qualified Data.Char as Char
46
47
#endif
47
48
48
- -- | Read a file into an 'InputStream'
49
+ -- | Read an encoded file into an 'InputStream'
49
50
readInputStream :: FilePath -> IO InputStream
50
51
{-# INLINE readInputStream #-}
51
52
52
53
-- | Read an 'InputStream' from a 'Handle'
53
54
hReadInputStream :: Handle -> IO InputStream
54
55
{-# INLINE hReadInputStream #-}
55
56
56
- -- | Convert 'InputStream' to 'String'
57
+ -- | Convert 'InputStream' to 'String'.
57
58
inputStreamToString :: InputStream -> String
58
59
{-# INLINE inputStreamToString #-}
59
60
60
- -- | Convert a 'String' to an 'InputStream'
61
+ -- | Convert a 'String' to an 'InputStream'.
61
62
inputStreamFromString :: String -> InputStream
62
63
{-# INLINE inputStreamFromString #-}
63
64
65
+ -- | Uses 'inputStreamFromString'
64
66
instance IsString InputStream where fromString = inputStreamFromString
65
67
66
68
-- | Read the first byte from an 'InputStream' and return that byte with what remains of the
67
- -- 'InputStream'. Should only be called when 'inputStreamEmpty' returns 'False'.
69
+ -- 'InputStream'. Behaviour is undefined when 'inputStreamEmpty' returns 'True'.
70
+ --
71
+ -- >>> takeByte "foo bar"
72
+ -- (102, "oo bar")
73
+ --
74
+ -- >>> takeByte "Ĥăƨĸëļļ"
75
+ -- (196, "\ETX\168\&8\235<<")
76
+ --
68
77
takeByte :: InputStream -> (Word8 , InputStream )
69
78
{-# INLINE takeByte #-}
70
79
71
80
-- | Read the first character from an 'InputStream' and return that 'Char' with what remains of the
72
- -- 'InputStream'. Should only be called when 'inputStreamEmpty' returns 'False'.
81
+ -- 'InputStream'. Behaviour is undefined when 'inputStreamEmpty' returns 'True'.
82
+ --
83
+ -- >>> takeChar "foo bar"
84
+ -- ('f', "oo bar")
85
+ --
86
+ -- >>> takeChar "Ĥăƨĸëļļ"
87
+ -- ('Ĥ', "ăƨĸëļļ")
88
+ --
73
89
takeChar :: InputStream -> (Char , InputStream )
74
90
{-# INLINE takeChar #-}
75
91
76
92
-- | Return @True@ if the given input stream is empty.
93
+ --
94
+ -- >>> inputStreamEmpty ""
95
+ -- True
96
+ --
97
+ -- >>> inputStreamEmpty "foo"
98
+ -- False
99
+ --
77
100
inputStreamEmpty :: InputStream -> Bool
78
101
{-# INLINE inputStreamEmpty #-}
79
102
80
103
-- | Returns the first @n@ characters of the given input stream, without removing them.
104
+ --
105
+ -- >>> peekChars 5 "foo bar"
106
+ -- "foo ba"
107
+ --
108
+ -- >>> peekChars 5 "foo"
109
+ -- "foo"
110
+ --
111
+ -- >>> peekChars 3 "Ĥăƨĸëļļ"
112
+ -- "Ĥăƨ"
113
+ --
81
114
peekChars :: Int -> InputStream -> String
82
115
{-# INLINE peekChars #-}
83
116
84
117
-- | Returns the number of text lines in the given 'InputStream'
118
+ --
119
+ -- >>> countLines ""
120
+ -- 0
121
+ --
122
+ -- >>> countLines "foo"
123
+ -- 1
124
+ --
125
+ -- >>> countLines "foo\n\nbar"
126
+ -- 3
127
+ --
128
+ -- >>> countLines "foo\n\nbar\n"
129
+ -- 3
130
+ --
85
131
countLines :: InputStream -> Int
86
132
{-# INLINE countLines #-}
87
133
88
134
#ifdef USE_BYTESTRING
89
135
90
136
-- | Opaque input type.
91
- newtype InputStream = IS BS. ByteString
137
+ newtype InputStream = IS BS. ByteString deriving ( Eq , Ord )
92
138
takeByte bs = (BS. head (coerce bs), coerce (BS. tail (coerce bs)))
93
139
takeChar bs = maybe (error " takeChar: no char left" ) coerce (BE. uncons (coerce bs))
94
140
inputStreamEmpty = BS. null . coerce
@@ -99,10 +145,13 @@ inputStreamToString = BE.toString . coerce
99
145
inputStreamFromString = IS . BE. fromString
100
146
countLines = length . BE. lines . coerce
101
147
148
+ instance Show InputStream where
149
+ show (IS bs) = show bs
150
+
102
151
#else
103
152
104
153
-- | Opaque input type.
105
- newtype InputStream = IS String
154
+ newtype InputStream = IS String deriving ( Eq , Ord )
106
155
takeByte (IS ~ (c: str))
107
156
| Char. isLatin1 c = let b = fromIntegral (Char. ord c) in b `seq` (b, IS str)
108
157
| otherwise = error " takeByte: not a latin-1 character"
@@ -115,4 +164,7 @@ inputStreamToString = coerce
115
164
inputStreamFromString = IS
116
165
countLines (IS str) = length . lines $ str
117
166
167
+ instance Show InputStream where
168
+ show (IS bs) = show bs
169
+
118
170
#endif
0 commit comments