1-- Parsing every integer width, the mirror of the builder's appends: what
2-- an append writes, the matching parse reads back. Each scans from the
3-- left and checks its bound before it multiplies, so a refusal is the
4-- first one the scan meets and no byte past it is read. A signed value
5-- is an optional `-` and digits, since no append writes a `+`.
6
7-- Decimal digits into a `u32` no greater than `limit`.
8scan_u32: (source: []u8, limit: u32)
9 -> (result: u32) ! invalid_number | number_overflow =
10 fail invalid_number when lenof source == 0
11 mut value: u32 = 0
12 for byte in source do
13 fail invalid_number when byte < 48 or byte > 57
14 digit: u32 = u32(byte - 48)
15 fail number_overflow when value > (limit - digit) / 10
16 value = value * 10 + digit
17 end for
18 result = value
19end scan_u32
20
21-- Decimal digits into a `u64` no greater than `limit`.
22scan_u64: (source: []u8, limit: u64)
23 -> (result: u64) ! invalid_number | number_overflow =
24 fail invalid_number when lenof source == 0
25 mut value: u64 = 0
26 for byte in source do
27 fail invalid_number when byte < 48 or byte > 57
28 digit: u64 = u64(byte - 48)
29 fail number_overflow when value > (limit - digit) / 10
30 value = value * 10 + digit
31 end for
32 result = value
33end scan_u64
34
35-- Decimal digits into a `usize` no greater than `limit`.
36scan_usize: (source: []u8, limit: usize)
37 -> (result: usize) ! invalid_number | number_overflow =
38 fail invalid_number when lenof source == 0
39 mut value: usize = 0
40 for byte in source do
41 fail invalid_number when byte < 48 or byte > 57
42 digit: usize = usize(byte - 48)
43 fail number_overflow when value > (limit - digit) / 10
44 value = value * 10 + digit
45 end for
46 result = value
47end scan_usize
48
49-- The digits after a leading `-`, or all of `source` without one.
50unsigned_part: (source: []u8) -> (digits: []u8 from source) =
51 digits = source
52 if lenof source > 0 and source[0] == 45 then
53 digits = source[1..<lenof source]
54 end if
55end unsigned_part
56
57-- Whether `source` begins with a `-`.
58negative: (source: []u8) -> (yes: bool) =
59 yes = lenof source > 0 and source[0] == 45
60end negative
61
62--- Parse nonempty ASCII decimal digits from bytes into `u8`, refusing as
63--- `parse_u32` does, with `number_overflow` above 255.
64public parse_u8: (source: []u8)
65 -> (result: u8) ! invalid_number | number_overflow =
66 result = u8(try scan_u32(source, 255))
67end parse_u8
68
69--- Parse nonempty ASCII decimal digits from bytes into `u16`, refusing as
70--- `parse_u32` does, with `number_overflow` above 65,535.
71public parse_u16: (source: []u8)
72 -> (result: u16) ! invalid_number | number_overflow =
73 result = u16(try scan_u32(source, 65535))
74end parse_u16
75
76--- Parse an `i8` from bytes: an optional `-` and nonempty ASCII decimal
77--- digits. Refuses an empty slice, a lone `-`, a `+`, whitespace and any
78--- other byte with `invalid_number`, and a value outside -128 to 127 with
79--- `number_overflow`, whichever the scan meets first.
80public parse_i8: (source: []u8)
81 -> (result: i8) ! invalid_number | number_overflow =
82 if negative(source) then
83 magnitude: u32 = try scan_u32(unsigned_part(source), 128)
84 result = i8(0 - i32(magnitude))
85 else
86 result = i8(try scan_u32(source, 127))
87 end if
88end parse_i8
89
90--- Parse an `i16` from bytes, as `parse_i8` does, within -32,768 to
91--- 32,767.
92public parse_i16: (source: []u8)
93 -> (result: i16) ! invalid_number | number_overflow =
94 if negative(source) then
95 magnitude: u32 = try scan_u32(unsigned_part(source), 32768)
96 result = i16(0 - i32(magnitude))
97 else
98 result = i16(try scan_u32(source, 32767))
99 end if
100end parse_i16
101
102--- Parse an `i32` from bytes, as `parse_i8` does, within `i32`'s range.
103public parse_i32: (source: []u8)
104 -> (result: i32) ! invalid_number | number_overflow =
105 if negative(source) then
106 magnitude: u32 = try scan_u32(unsigned_part(source), 2147483648)
107 if magnitude == 2147483648 then
108 result = 0 - 2147483647 - 1
109 else
110 result = 0 - i32(magnitude)
111 end if
112 else
113 result = i32(try scan_u32(source, 2147483647))
114 end if
115end parse_i32
116
117--- Parse an `i64` from bytes, as `parse_i8` does, within `i64`'s range.
118public parse_i64: (source: []u8)
119 -> (result: i64) ! invalid_number | number_overflow =
120 if negative(source) then
121 magnitude: u64 = try scan_u64(unsigned_part(source),
122 9223372036854775808)
123 if magnitude == 9223372036854775808 then
124 result = 0 - 9223372036854775807 - 1
125 else
126 result = 0 - i64(magnitude)
127 end if
128 else
129 result = i64(try scan_u64(source, 9223372036854775807))
130 end if
131end parse_i64
132
133--- Parse an `isize` from bytes, as `parse_i8` does, within the target's
134--- `isize` range, so the same digits can parse on a 64-bit target and
135--- overflow on a 32-bit one.
136public parse_isize: (source: []u8)
137 -> (result: isize) ! invalid_number | number_overflow =
138 largest: usize = (0 -% 1) >> 1
139 if negative(source) then
140 magnitude: usize = try scan_usize(unsigned_part(source), largest + 1)
141 if magnitude == largest + 1 then
142 result = 0 - isize(largest) - 1
143 else
144 result = 0 - isize(magnitude)
145 end if
146 else
147 result = isize(try scan_usize(source, largest))
148 end if
149end parse_isize
150
151-- A hexadecimal digit's value, or 16 for a byte that is not one.
152hex_value: (byte: u8) -> (value: u8) =
153 value = 16
154 if byte >= 48 and byte <= 57 then
155 value = byte - 48
156 elsif byte >= 97 and byte <= 102 then
157 value = byte - 87
158 elsif byte >= 65 and byte <= 70 then
159 value = byte - 55
160 end if
161end hex_value
162
163--- Parse nonempty hexadecimal digits from bytes into `u32`: `0` to `9`
164--- and `a` to `f` in either case, with no `0x`, sign or space. Refuses
165--- any other byte or an empty slice with `invalid_number` and a value
166--- above `u32`'s maximum with `number_overflow`, whichever the scan meets
167--- first.
168public parse_hex_u32: (source: []u8)
169 -> (result: u32) ! invalid_number | number_overflow =
170 fail invalid_number when lenof source == 0
171 mut value: u32 = 0
172 for byte in source do
173 digit: u8 = hex_value(byte)
174 fail invalid_number when digit == 16
175 fail number_overflow when value > u32(0 -% 1) >> 4
176 value = (value << 4) | u32(digit)
177 end for
178 result = value
179end parse_hex_u32
180
181--- Parse hexadecimal digits from bytes into `u64`, as `parse_hex_u32`
182--- does.
183public parse_hex_u64: (source: []u8)
184 -> (result: u64) ! invalid_number | number_overflow =
185 fail invalid_number when lenof source == 0
186 mut value: u64 = 0
187 for byte in source do
188 digit: u8 = hex_value(byte)
189 fail invalid_number when digit == 16
190 fail number_overflow when value > u64(0 -% 1) >> 4
191 value = (value << 4) | u64(digit)
192 end for
193 result = value
194end parse_hex_u64
195
196--- Parse hexadecimal digits from bytes into `usize`, as `parse_hex_u32`
197--- does, at the target's width.
198public parse_hex_usize: (source: []u8)
199 -> (result: usize) ! invalid_number | number_overflow =
200 fail invalid_number when lenof source == 0
201 mut value: usize = 0
202 for byte in source do
203 digit: u8 = hex_value(byte)
204 fail invalid_number when digit == 16
205 fail number_overflow when value > usize(0 -% 1) >> 4
206 value = (value << 4) | usize(digit)
207 end for
208 result = value
209end parse_hex_usize