0 | module Text.TOML.Lexer
3 | import Data.ByteString
6 | import Text.TOML.Types
7 | import Text.ILex.RExp
8 | import Text.ILex.Util
24 | wschar = ' ' || '\t'
30 | newline = '\n' <|> "\r\n"
34 | nonAscii : RExp True
35 | nonAscii = range32 0x80 0xD7FF || range32 0xE000 0x10FFFF
42 | comment = '#' >> star ('\t' || range32 0x20 0x7E || nonAscii)
50 | unquotedKey : RExp True
51 | unquotedKey = plus (alphaNum || '-' || '_')
55 | literalChars : RExp True
56 | literalChars = plus $
'\t' || range32 0x20 0x26 || range32 0x28 0x7e || nonAscii
60 | basicUnescaped : RExp True
62 | wschar || '!' || range32 0x23 0x5b || range32 0x5d 0x7e || nonAscii
66 | mlbEscapedNL : RExp True
68 | '\\' >> star wschar >> newline >> star (wschar <|> newline)
75 | mp = opt $
oneof ['-', '+']
81 | decInt = mp >> ('0' <|> (posdigit >> star (opt '_' >> digit)))
86 | binInt = "0b" >> bindigit >> star (opt '_' >> bindigit)
91 | octInt = "0o" >> octdigit >> star (opt '_' >> octdigit)
96 | hexInt = "0x" >> hexdigit >> star (opt '_' >> hexdigit)
99 | readDecInt : ByteString -> Integer
100 | readDecInt (BS 0 _) = 0
101 | readDecInt bs@(BS (S k) bv) =
103 | 43 => decimalSep underscore (BS k $
tail bv)
104 | 45 => negate $
decimalSep underscore (BS k $
tail bv)
105 | _ => decimalSep underscore bs
113 | posInf = opt '+' >> "inf"
124 | float = decInt >> (exp <|> (frac >> opt exp))
126 | frac, exp, zeroPrefixableInt : RExp True
127 | frac = '.' >> zeroPrefixableInt
128 | exp = ('e' <|> 'E') >> mp >> zeroPrefixableInt
129 | zeroPrefixableInt = digit >> star (opt '_' >> digit)
132 | readFloat : ByteString -> TomlFloat
134 | Float $
case unpack $
toString bs of
135 | '+' :: t => go [<] t
138 | go : SnocList Char -> List Char -> Double
139 | go sc [] = cast $
pack (sc <>> [])
140 | go sc ('_'::cs) = go sc cs
141 | go sc ('E'::cs) = go (sc:<'e') cs
142 | go sc (c::cs) = go (sc:<c) cs
149 | readInt : (Integer -> Maybe a) -> a -> ByteString -> a
150 | readInt f v = fromMaybe v . f . decimal
158 | fullDate : RExp True
159 | fullDate = repeat 4 digit >> '-' >> month_day
161 | d29,d30,d31,month_day : RExp True
162 | d29 = ('0' >> posdigit) <|> (oneof ['1','2'] >> digit)
167 | (("01"<|>"03"<|>"05"<|>"07"<|>"08"<|>"10"<|>"12") >> '-' >> d31)
168 | <|> (("04"<|>"06"<|>"09"<|>"11") >> '-' >> d30)
172 | readLocalDate : ByteString -> LocalDate
174 | let y := readInt refineYear 0 (take 4 bs)
175 | m := readInt intToMonth JAN (take 2 $
drop 5 bs)
176 | in case refineDay {m} (decimal $
take 2 $
drop 8 bs) of
177 | Just d => MkDate y m d
178 | Nothing => MkDate y JAN 1
181 | timeHour : RExp True
182 | timeHour = (oneof ['0','1'] >> digit) <|> ('2' >> range '0' '3')
185 | timeMinute : RExp True
186 | timeMinute = range '0' '5' >> digit
192 | localTime : RExp True
193 | localTime = timeHour >> ':' >> timeMinute >> ':' >> sec >> opt frac
195 | sec,frac : RExp True
196 | sec = timeMinute <|> "60"
197 | frac = '.' >> plus digit
200 | readLocalTime : ByteString -> LocalTime
202 | let h := readInt refineHour 0 (take 2 bs)
203 | m := readInt refineMinute 0 (take 2 $
drop 3 bs)
204 | s := readInt refineSecond 0 (take 2 $
drop 6 bs)
205 | in case drop 8 bs of
206 | BS 0 _ => LT h m s Nothing
207 | bs@(BS (S k) bv) => case bv `at` 0 of
209 | let bs' := padRight 6 byte_0 $
takeWhile isDigit (BS k $
tail bv)
210 | in LT h m s $
Just $
readInt refineMicroSecond 0 bs'
211 | _ => LT h m s Nothing
216 | localDateTime : RExp True
217 | localDateTime = fullDate >> oneof ['T','t',' '] >> localTime
220 | readLocalDateTime : ByteString -> LocalDateTime
221 | readLocalDateTime bs =
222 | let fd := readLocalDate bs
223 | in LDT fd (readLocalTime $
drop 11 bs)
230 | offsetDateTime : RExp True
232 | let timeNumoffset := oneof ['+','-'] >> timeHour >> ':' >> timeMinute
233 | in localDateTime >> ('Z' <|> 'z' <|> timeNumoffset)
236 | readOffsetDateTime : ByteString -> OffsetDateTime
237 | readOffsetDateTime bs =
238 | let LDT d t := readLocalDateTime bs
239 | in ODT d (OT t offset)
244 | let bs2@(BS (S _) bv) := takeEnd 6 bs | _ => Z
249 | let h := readInt refineHour 0 (take 2 $
drop 1 bs2)
250 | m := readInt refineMinute 0 (take 2 $
drop 4 bs2)
251 | x := if at bv 0 == 43 then Plus else Minus