| ... | ... | @@ -414,7 +414,7 @@ pub const Scanner = struct { |
| 414 | 414 | string_is_object_key: bool = false, |
| 415 | 415 | stack: BitStack, |
| 416 | 416 | value_start: usize = undefined, |
| 417 | | unicode_code_point: u21 = undefined, |
| 417 | utf16_code_units: [2]u16 = undefined, |
| 418 | 418 | |
| 419 | 419 | input: []const u8 = "", |
| 420 | 420 | cursor: usize = 0, |
| ... | ... | @@ -1083,13 +1083,13 @@ pub const Scanner = struct { |
| 1083 | 1083 | const c = try self.expectByte(); |
| 1084 | 1084 | switch (c) { |
| 1085 | 1085 | '0'...'9' => { |
| 1086 | | self.unicode_code_point = @as(u21, c - '0') << 12; |
| 1086 | self.utf16_code_units[0] = @as(u16, c - '0') << 12; |
| 1087 | 1087 | }, |
| 1088 | 1088 | 'A'...'F' => { |
| 1089 | | self.unicode_code_point = @as(u21, c - 'A' + 10) << 12; |
| 1089 | self.utf16_code_units[0] = @as(u16, c - 'A' + 10) << 12; |
| 1090 | 1090 | }, |
| 1091 | 1091 | 'a'...'f' => { |
| 1092 | | self.unicode_code_point = @as(u21, c - 'a' + 10) << 12; |
| 1092 | self.utf16_code_units[0] = @as(u16, c - 'a' + 10) << 12; |
| 1093 | 1093 | }, |
| 1094 | 1094 | else => return error.SyntaxError, |
| 1095 | 1095 | } |
| ... | ... | @@ -1101,13 +1101,13 @@ pub const Scanner = struct { |
| 1101 | 1101 | const c = try self.expectByte(); |
| 1102 | 1102 | switch (c) { |
| 1103 | 1103 | '0'...'9' => { |
| 1104 | | self.unicode_code_point |= @as(u21, c - '0') << 8; |
| 1104 | self.utf16_code_units[0] |= @as(u16, c - '0') << 8; |
| 1105 | 1105 | }, |
| 1106 | 1106 | 'A'...'F' => { |
| 1107 | | self.unicode_code_point |= @as(u21, c - 'A' + 10) << 8; |
| 1107 | self.utf16_code_units[0] |= @as(u16, c - 'A' + 10) << 8; |
| 1108 | 1108 | }, |
| 1109 | 1109 | 'a'...'f' => { |
| 1110 | | self.unicode_code_point |= @as(u21, c - 'a' + 10) << 8; |
| 1110 | self.utf16_code_units[0] |= @as(u16, c - 'a' + 10) << 8; |
| 1111 | 1111 | }, |
| 1112 | 1112 | else => return error.SyntaxError, |
| 1113 | 1113 | } |
| ... | ... | @@ -1119,13 +1119,13 @@ pub const Scanner = struct { |
| 1119 | 1119 | const c = try self.expectByte(); |
| 1120 | 1120 | switch (c) { |
| 1121 | 1121 | '0'...'9' => { |
| 1122 | | self.unicode_code_point |= @as(u21, c - '0') << 4; |
| 1122 | self.utf16_code_units[0] |= @as(u16, c - '0') << 4; |
| 1123 | 1123 | }, |
| 1124 | 1124 | 'A'...'F' => { |
| 1125 | | self.unicode_code_point |= @as(u21, c - 'A' + 10) << 4; |
| 1125 | self.utf16_code_units[0] |= @as(u16, c - 'A' + 10) << 4; |
| 1126 | 1126 | }, |
| 1127 | 1127 | 'a'...'f' => { |
| 1128 | | self.unicode_code_point |= @as(u21, c - 'a' + 10) << 4; |
| 1128 | self.utf16_code_units[0] |= @as(u16, c - 'a' + 10) << 4; |
| 1129 | 1129 | }, |
| 1130 | 1130 | else => return error.SyntaxError, |
| 1131 | 1131 | } |
| ... | ... | @@ -1137,31 +1137,26 @@ pub const Scanner = struct { |
| 1137 | 1137 | const c = try self.expectByte(); |
| 1138 | 1138 | switch (c) { |
| 1139 | 1139 | '0'...'9' => { |
| 1140 | | self.unicode_code_point |= c - '0'; |
| 1140 | self.utf16_code_units[0] |= c - '0'; |
| 1141 | 1141 | }, |
| 1142 | 1142 | 'A'...'F' => { |
| 1143 | | self.unicode_code_point |= c - 'A' + 10; |
| 1143 | self.utf16_code_units[0] |= c - 'A' + 10; |
| 1144 | 1144 | }, |
| 1145 | 1145 | 'a'...'f' => { |
| 1146 | | self.unicode_code_point |= c - 'a' + 10; |
| 1146 | self.utf16_code_units[0] |= c - 'a' + 10; |
| 1147 | 1147 | }, |
| 1148 | 1148 | else => return error.SyntaxError, |
| 1149 | 1149 | } |
| 1150 | 1150 | self.cursor += 1; |
| 1151 | | switch (self.unicode_code_point) { |
| 1152 | | 0xD800...0xDBFF => { |
| 1153 | | // High surrogate half. |
| 1154 | | self.unicode_code_point = 0x10000 | (self.unicode_code_point << 10); |
| 1155 | | self.state = .string_surrogate_half; |
| 1156 | | continue :state_loop; |
| 1157 | | }, |
| 1158 | | 0xDC00...0xDFFF => return error.SyntaxError, // Unexpected low surrogate half. |
| 1159 | | else => { |
| 1160 | | // Code point from a single UTF-16 code unit. |
| 1161 | | self.value_start = self.cursor; |
| 1162 | | self.state = .string; |
| 1163 | | return self.partialStringCodepoint(); |
| 1164 | | }, |
| 1151 | if (std.unicode.utf16IsHighSurrogate(self.utf16_code_units[0])) { |
| 1152 | self.state = .string_surrogate_half; |
| 1153 | continue :state_loop; |
| 1154 | } else if (std.unicode.utf16IsLowSurrogate(self.utf16_code_units[0])) { |
| 1155 | return error.SyntaxError; // Unexpected low surrogate half. |
| 1156 | } else { |
| 1157 | self.value_start = self.cursor; |
| 1158 | self.state = .string; |
| 1159 | return partialStringCodepoint(self.utf16_code_units[0]); |
| 1165 | 1160 | } |
| 1166 | 1161 | }, |
| 1167 | 1162 | .string_surrogate_half => { |
| ... | ... | @@ -1188,6 +1183,7 @@ pub const Scanner = struct { |
| 1188 | 1183 | switch (try self.expectByte()) { |
| 1189 | 1184 | 'D', 'd' => { |
| 1190 | 1185 | self.cursor += 1; |
| 1186 | self.utf16_code_units[1] = 0xD << 12; |
| 1191 | 1187 | self.state = .string_surrogate_half_backslash_u_1; |
| 1192 | 1188 | continue :state_loop; |
| 1193 | 1189 | }, |
| ... | ... | @@ -1199,13 +1195,13 @@ pub const Scanner = struct { |
| 1199 | 1195 | switch (c) { |
| 1200 | 1196 | 'C'...'F' => { |
| 1201 | 1197 | self.cursor += 1; |
| 1202 | | self.unicode_code_point |= @as(u21, c - 'C') << 8; |
| 1198 | self.utf16_code_units[1] |= @as(u16, c - 'A' + 10) << 8; |
| 1203 | 1199 | self.state = .string_surrogate_half_backslash_u_2; |
| 1204 | 1200 | continue :state_loop; |
| 1205 | 1201 | }, |
| 1206 | 1202 | 'c'...'f' => { |
| 1207 | 1203 | self.cursor += 1; |
| 1208 | | self.unicode_code_point |= @as(u21, c - 'c') << 8; |
| 1204 | self.utf16_code_units[1] |= @as(u16, c - 'a' + 10) << 8; |
| 1209 | 1205 | self.state = .string_surrogate_half_backslash_u_2; |
| 1210 | 1206 | continue :state_loop; |
| 1211 | 1207 | }, |
| ... | ... | @@ -1217,19 +1213,19 @@ pub const Scanner = struct { |
| 1217 | 1213 | switch (c) { |
| 1218 | 1214 | '0'...'9' => { |
| 1219 | 1215 | self.cursor += 1; |
| 1220 | | self.unicode_code_point |= @as(u21, c - '0') << 4; |
| 1216 | self.utf16_code_units[1] |= @as(u16, c - '0') << 4; |
| 1221 | 1217 | self.state = .string_surrogate_half_backslash_u_3; |
| 1222 | 1218 | continue :state_loop; |
| 1223 | 1219 | }, |
| 1224 | 1220 | 'A'...'F' => { |
| 1225 | 1221 | self.cursor += 1; |
| 1226 | | self.unicode_code_point |= @as(u21, c - 'A' + 10) << 4; |
| 1222 | self.utf16_code_units[1] |= @as(u16, c - 'A' + 10) << 4; |
| 1227 | 1223 | self.state = .string_surrogate_half_backslash_u_3; |
| 1228 | 1224 | continue :state_loop; |
| 1229 | 1225 | }, |
| 1230 | 1226 | 'a'...'f' => { |
| 1231 | 1227 | self.cursor += 1; |
| 1232 | | self.unicode_code_point |= @as(u21, c - 'a' + 10) << 4; |
| 1228 | self.utf16_code_units[1] |= @as(u16, c - 'a' + 10) << 4; |
| 1233 | 1229 | self.state = .string_surrogate_half_backslash_u_3; |
| 1234 | 1230 | continue :state_loop; |
| 1235 | 1231 | }, |
| ... | ... | @@ -1240,20 +1236,21 @@ pub const Scanner = struct { |
| 1240 | 1236 | const c = try self.expectByte(); |
| 1241 | 1237 | switch (c) { |
| 1242 | 1238 | '0'...'9' => { |
| 1243 | | self.unicode_code_point |= c - '0'; |
| 1239 | self.utf16_code_units[1] |= c - '0'; |
| 1244 | 1240 | }, |
| 1245 | 1241 | 'A'...'F' => { |
| 1246 | | self.unicode_code_point |= c - 'A' + 10; |
| 1242 | self.utf16_code_units[1] |= c - 'A' + 10; |
| 1247 | 1243 | }, |
| 1248 | 1244 | 'a'...'f' => { |
| 1249 | | self.unicode_code_point |= c - 'a' + 10; |
| 1245 | self.utf16_code_units[1] |= c - 'a' + 10; |
| 1250 | 1246 | }, |
| 1251 | 1247 | else => return error.SyntaxError, |
| 1252 | 1248 | } |
| 1253 | 1249 | self.cursor += 1; |
| 1254 | 1250 | self.value_start = self.cursor; |
| 1255 | 1251 | self.state = .string; |
| 1256 | | return self.partialStringCodepoint(); |
| 1252 | const code_point = std.unicode.utf16DecodeSurrogatePair(&self.utf16_code_units) catch unreachable; |
| 1253 | return partialStringCodepoint(code_point); |
| 1257 | 1254 | }, |
| 1258 | 1255 | |
| 1259 | 1256 | .string_utf8_last_byte => { |
| ... | ... | @@ -1681,9 +1678,7 @@ pub const Scanner = struct { |
| 1681 | 1678 | return Token{ .partial_number = slice }; |
| 1682 | 1679 | } |
| 1683 | 1680 | |
| 1684 | | fn partialStringCodepoint(self: *@This()) Token { |
| 1685 | | const code_point = self.unicode_code_point; |
| 1686 | | self.unicode_code_point = undefined; |
| 1681 | fn partialStringCodepoint(code_point: u21) Token { |
| 1687 | 1682 | var buf: [4]u8 = undefined; |
| 1688 | 1683 | switch (std.unicode.utf8Encode(code_point, &buf) catch unreachable) { |
| 1689 | 1684 | 1 => return Token{ .partial_string_escaped_1 = buf[0..1].* }, |