@@ -17,12 +17,60 @@ private def chars_to_string (xs : Array Char) : String :=
1717
1818@[always_inline, specialize]
1919def satisfy (p : Char → Bool) : Get Char := do
20- let b ← getThe UInt8
21- let c := byteToChar b
22- if p c then
23- return c
20+ let b ← pending (getThe UInt8)
21+ let b1 := UInt8.toUInt32 b
22+ if b1 <= 127 then
23+ let c := Char.ofNat b.toNat
24+ if p c then
25+ return c
26+ else
27+ fail " unexpected byte"
28+ else if 194 ≤ b1 && b1 ≤ 223 then -- 2-byte sequence
29+ let b2 ← pending (getThe UInt8)
30+ let b2u := UInt8.toUInt32 b2
31+ if (b2u &&& 192 ) != 128 then fail " invalid utf8 continuation"
32+ let cp := ((b1 &&& 31 ) <<< 6 ) ||| (b2u &&& 63 )
33+ let c := Char.ofNat cp.toNat
34+ if p c then
35+ return c
36+ else
37+ fail " unexpected byte"
38+ else if 224 ≤ b1 && b1 ≤ 239 then -- 3-byte sequence
39+ let b2 ← pending (getThe UInt8)
40+ let b3 ← pending (getThe UInt8)
41+ let b2u := UInt8.toUInt32 b2
42+ let b3u := UInt8.toUInt32 b3
43+ if (b2u &&& 192 ) != 128 || (b3u &&& 192 ) != 128 then fail " invalid utf8 continuation"
44+ -- prevent overlongs and surrogates
45+ if b1 == 224 && b2u < 160 then fail " overlong utf8 sequence"
46+ if b1 == 237 && b2u > 159 then fail " utf8 surrogate"
47+ let cp := ((b1 &&& 15 ) <<< 12 ) ||| ((b2u &&& 63 ) <<< 6 ) ||| (b3u &&& 63 )
48+ let c := Char.ofNat cp.toNat
49+ if p c then
50+ return c
51+ else
52+ fail " unexpected byte"
53+ else if 240 ≤ b1 && b1 ≤ 244 then -- 4-byte sequence
54+ let b2 ← pending (getThe UInt8)
55+ let b3 ← pending (getThe UInt8)
56+ let b4 ← pending (getThe UInt8)
57+ let b2u := UInt8.toUInt32 b2
58+ let b3u := UInt8.toUInt32 b3
59+ let b4u := UInt8.toUInt32 b4
60+ if (b2u &&& 192 ) != 128 || (b3u &&& 192 ) != 128 || (b4u &&& 192 ) != 128 then
61+ fail " invalid utf8 continuation"
62+ if b1 == 240 && b2u < 144 then fail " overlong utf8 sequence"
63+ if b1 == 244 && b2u > 143 then fail " utf8 codepoint too large"
64+ let cp := ((b1 &&& 7 ) <<< 18 ) ||| ((b2u &&& 63 ) <<< 12 ) ||| ((b3u &&& 63 ) <<< 6 ) ||| (b4u &&& 63 )
65+ let cpNat := cp.toNat
66+ if cpNat > 0x10FFFF then fail " utf8 codepoint out of range"
67+ let c := Char.ofNat cpNat
68+ if p c then
69+ return c
70+ else
71+ fail " unexpected byte"
2472 else
25- fail " unexpected byte"
73+ fail " invalid utf8 leading byte"
2674
2775@[always_inline]
2876def pchar (c : Char) : Get Char := satisfy (· == c)
0 commit comments