| ... | ... | @@ -190,6 +190,7 @@ enum TokenizeState { |
| 190 | 190 | TokenizeStateFloatExponentNumber, // "123.456e-", "123.456e5", "123.456e5e-5" |
| 191 | 191 | TokenizeStateString, |
| 192 | 192 | TokenizeStateStringEscape, |
| 193 | TokenizeStateStringEscapeUnicodeStart, |
| 193 | 194 | TokenizeStateCharLiteral, |
| 194 | 195 | TokenizeStateCharLiteralEnd, |
| 195 | 196 | TokenizeStateSawStar, |
| ... | ... | @@ -241,7 +242,6 @@ struct Tokenize { |
| 241 | 242 | int32_t exp_add_amt; |
| 242 | 243 | bool is_exp_negative; |
| 243 | 244 | size_t char_code_index; |
| 244 | | size_t char_code_end; |
| 245 | 245 | bool unicode; |
| 246 | 246 | uint32_t char_code; |
| 247 | 247 | int exponent_in_bin_or_dec; |
| ... | ... | @@ -1071,24 +1071,10 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1071 | 1071 | t.radix = 16; |
| 1072 | 1072 | t.char_code = 0; |
| 1073 | 1073 | t.char_code_index = 0; |
| 1074 | | t.char_code_end = 2; |
| 1075 | 1074 | t.unicode = false; |
| 1076 | 1075 | break; |
| 1077 | 1076 | case 'u': |
| 1078 | | t.state = TokenizeStateCharCode; |
| 1079 | | t.radix = 16; |
| 1080 | | t.char_code = 0; |
| 1081 | | t.char_code_index = 0; |
| 1082 | | t.char_code_end = 4; |
| 1083 | | t.unicode = true; |
| 1084 | | break; |
| 1085 | | case 'U': |
| 1086 | | t.state = TokenizeStateCharCode; |
| 1087 | | t.radix = 16; |
| 1088 | | t.char_code = 0; |
| 1089 | | t.char_code_index = 0; |
| 1090 | | t.char_code_end = 6; |
| 1091 | | t.unicode = true; |
| 1077 | t.state = TokenizeStateStringEscapeUnicodeStart; |
| 1092 | 1078 | break; |
| 1093 | 1079 | case 'n': |
| 1094 | 1080 | handle_string_escape(&t, '\n'); |
| ... | ... | @@ -1112,8 +1098,63 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1112 | 1098 | invalid_char_error(&t, c); |
| 1113 | 1099 | } |
| 1114 | 1100 | break; |
| 1101 | case TokenizeStateStringEscapeUnicodeStart: |
| 1102 | switch (c) { |
| 1103 | case '{': |
| 1104 | t.state = TokenizeStateCharCode; |
| 1105 | t.radix = 16; |
| 1106 | t.char_code = 0; |
| 1107 | t.char_code_index = 0; |
| 1108 | t.unicode = true; |
| 1109 | break; |
| 1110 | default: |
| 1111 | invalid_char_error(&t, c); |
| 1112 | } |
| 1113 | break; |
| 1115 | 1114 | case TokenizeStateCharCode: |
| 1116 | 1115 | { |
| 1116 | if (t.unicode && c == '}') { |
| 1117 | if (t.char_code_index == 0) { |
| 1118 | tokenize_error(&t, "empty unicode escape sequence"); |
| 1119 | break; |
| 1120 | } |
| 1121 | if (t.char_code > 0x10ffff) { |
| 1122 | tokenize_error(&t, "unicode value out of range: %x", t.char_code); |
| 1123 | break; |
| 1124 | } |
| 1125 | if (t.cur_tok->id == TokenIdCharLiteral) { |
| 1126 | t.cur_tok->data.char_lit.c = t.char_code; |
| 1127 | t.state = TokenizeStateCharLiteralEnd; |
| 1128 | } else if (t.char_code <= 0x7f) { |
| 1129 | // 00000000 00000000 00000000 0xxxxxxx |
| 1130 | handle_string_escape(&t, (uint8_t)t.char_code); |
| 1131 | } else if (t.char_code <= 0x7ff) { |
| 1132 | // 00000000 00000000 00000xxx xx000000 |
| 1133 | handle_string_escape(&t, (uint8_t)(0xc0 | (t.char_code >> 6))); |
| 1134 | // 00000000 00000000 00000000 00xxxxxx |
| 1135 | handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); |
| 1136 | } else if (t.char_code <= 0xffff) { |
| 1137 | // 00000000 00000000 xxxx0000 00000000 |
| 1138 | handle_string_escape(&t, (uint8_t)(0xe0 | (t.char_code >> 12))); |
| 1139 | // 00000000 00000000 0000xxxx xx000000 |
| 1140 | handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); |
| 1141 | // 00000000 00000000 00000000 00xxxxxx |
| 1142 | handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); |
| 1143 | } else if (t.char_code <= 0x10ffff) { |
| 1144 | // 00000000 000xxx00 00000000 00000000 |
| 1145 | handle_string_escape(&t, (uint8_t)(0xf0 | (t.char_code >> 18))); |
| 1146 | // 00000000 000000xx xxxx0000 00000000 |
| 1147 | handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 12) & 0x3f))); |
| 1148 | // 00000000 00000000 0000xxxx xx000000 |
| 1149 | handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); |
| 1150 | // 00000000 00000000 00000000 00xxxxxx |
| 1151 | handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); |
| 1152 | } else { |
| 1153 | zig_unreachable(); |
| 1154 | } |
| 1155 | break; |
| 1156 | } |
| 1157 | |
| 1117 | 1158 | uint32_t digit_value = get_digit_value(c); |
| 1118 | 1159 | if (digit_value >= t.radix) { |
| 1119 | 1160 | tokenize_error(&t, "invalid digit: '%c'", c); |
| ... | ... | @@ -1123,44 +1164,9 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1123 | 1164 | t.char_code += digit_value; |
| 1124 | 1165 | t.char_code_index += 1; |
| 1125 | 1166 | |
| 1126 | | if (t.char_code_index >= t.char_code_end) { |
| 1127 | | if (t.unicode) { |
| 1128 | | if (t.char_code > 0x10ffff) { |
| 1129 | | tokenize_error(&t, "unicode value out of range: %x", t.char_code); |
| 1130 | | break; |
| 1131 | | } |
| 1132 | | if (t.cur_tok->id == TokenIdCharLiteral) { |
| 1133 | | t.cur_tok->data.char_lit.c = t.char_code; |
| 1134 | | t.state = TokenizeStateCharLiteralEnd; |
| 1135 | | } else if (t.char_code <= 0x7f) { |
| 1136 | | // 00000000 00000000 00000000 0xxxxxxx |
| 1137 | | handle_string_escape(&t, (uint8_t)t.char_code); |
| 1138 | | } else if (t.char_code <= 0x7ff) { |
| 1139 | | // 00000000 00000000 00000xxx xx000000 |
| 1140 | | handle_string_escape(&t, (uint8_t)(0xc0 | (t.char_code >> 6))); |
| 1141 | | // 00000000 00000000 00000000 00xxxxxx |
| 1142 | | handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); |
| 1143 | | } else if (t.char_code <= 0xffff) { |
| 1144 | | // 00000000 00000000 xxxx0000 00000000 |
| 1145 | | handle_string_escape(&t, (uint8_t)(0xe0 | (t.char_code >> 12))); |
| 1146 | | // 00000000 00000000 0000xxxx xx000000 |
| 1147 | | handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); |
| 1148 | | // 00000000 00000000 00000000 00xxxxxx |
| 1149 | | handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); |
| 1150 | | } else if (t.char_code <= 0x10ffff) { |
| 1151 | | // 00000000 000xxx00 00000000 00000000 |
| 1152 | | handle_string_escape(&t, (uint8_t)(0xf0 | (t.char_code >> 18))); |
| 1153 | | // 00000000 000000xx xxxx0000 00000000 |
| 1154 | | handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 12) & 0x3f))); |
| 1155 | | // 00000000 00000000 0000xxxx xx000000 |
| 1156 | | handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); |
| 1157 | | // 00000000 00000000 00000000 00xxxxxx |
| 1158 | | handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); |
| 1159 | | } |
| 1160 | | } else { |
| 1161 | | assert(t.char_code <= 255); |
| 1162 | | handle_string_escape(&t, (uint8_t)t.char_code); |
| 1163 | | } |
| 1167 | if (!t.unicode && t.char_code_index >= 2) { |
| 1168 | assert(t.char_code <= 255); |
| 1169 | handle_string_escape(&t, (uint8_t)t.char_code); |
| 1164 | 1170 | } |
| 1165 | 1171 | } |
| 1166 | 1172 | break; |
| ... | ... | @@ -1409,6 +1415,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1409 | 1415 | tokenize_error(&t, "unterminated string"); |
| 1410 | 1416 | break; |
| 1411 | 1417 | case TokenizeStateStringEscape: |
| 1418 | case TokenizeStateStringEscapeUnicodeStart: |
| 1412 | 1419 | case TokenizeStateCharCode: |
| 1413 | 1420 | if (t.cur_tok->id == TokenIdStringLiteral) { |
| 1414 | 1421 | tokenize_error(&t, "unterminated string"); |