| ... | @@ -190,6 +190,7 @@ enum TokenizeState { | ... | @@ -190,6 +190,7 @@ enum TokenizeState { |
| 190 | TokenizeStateFloatExponentNumber, // "123.456e-", "123.456e5", "123.456e5e-5" | 190 | TokenizeStateFloatExponentNumber, // "123.456e-", "123.456e5", "123.456e5e-5" |
| 191 | TokenizeStateString, | 191 | TokenizeStateString, |
| 192 | TokenizeStateStringEscape, | 192 | TokenizeStateStringEscape, |
| | 193 | TokenizeStateStringEscapeUnicodeStart, |
| 193 | TokenizeStateCharLiteral, | 194 | TokenizeStateCharLiteral, |
| 194 | TokenizeStateCharLiteralEnd, | 195 | TokenizeStateCharLiteralEnd, |
| 195 | TokenizeStateSawStar, | 196 | TokenizeStateSawStar, |
| ... | @@ -241,7 +242,6 @@ struct Tokenize { | ... | @@ -241,7 +242,6 @@ struct Tokenize { |
| 241 | int32_t exp_add_amt; | 242 | int32_t exp_add_amt; |
| 242 | bool is_exp_negative; | 243 | bool is_exp_negative; |
| 243 | size_t char_code_index; | 244 | size_t char_code_index; |
| 244 | size_t char_code_end; | | |
| 245 | bool unicode; | 245 | bool unicode; |
| 246 | uint32_t char_code; | 246 | uint32_t char_code; |
| 247 | int exponent_in_bin_or_dec; | 247 | int exponent_in_bin_or_dec; |
| ... | @@ -1071,24 +1071,10 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -1071,24 +1071,10 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1071 | t.radix = 16; | 1071 | t.radix = 16; |
| 1072 | t.char_code = 0; | 1072 | t.char_code = 0; |
| 1073 | t.char_code_index = 0; | 1073 | t.char_code_index = 0; |
| 1074 | t.char_code_end = 2; | | |
| 1075 | t.unicode = false; | 1074 | t.unicode = false; |
| 1076 | break; | 1075 | break; |
| 1077 | case 'u': | 1076 | case 'u': |
| 1078 | t.state = TokenizeStateCharCode; | 1077 | t.state = TokenizeStateStringEscapeUnicodeStart; |
| 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; | | |
| 1092 | break; | 1078 | break; |
| 1093 | case 'n': | 1079 | case 'n': |
| 1094 | handle_string_escape(&t, '\n'); | 1080 | handle_string_escape(&t, '\n'); |
| ... | @@ -1112,8 +1098,63 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -1112,8 +1098,63 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1112 | invalid_char_error(&t, c); | 1098 | invalid_char_error(&t, c); |
| 1113 | } | 1099 | } |
| 1114 | break; | 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 | case TokenizeStateCharCode: | 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 | uint32_t digit_value = get_digit_value(c); | 1158 | uint32_t digit_value = get_digit_value(c); |
| 1118 | if (digit_value >= t.radix) { | 1159 | if (digit_value >= t.radix) { |
| 1119 | tokenize_error(&t, "invalid digit: '%c'", c); | 1160 | tokenize_error(&t, "invalid digit: '%c'", c); |
| ... | @@ -1123,44 +1164,9 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -1123,44 +1164,9 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1123 | t.char_code += digit_value; | 1164 | t.char_code += digit_value; |
| 1124 | t.char_code_index += 1; | 1165 | t.char_code_index += 1; |
| 1125 | | 1166 | |
| 1126 | if (t.char_code_index >= t.char_code_end) { | 1167 | if (!t.unicode && t.char_code_index >= 2) { |
| 1127 | if (t.unicode) { | 1168 | assert(t.char_code <= 255); |
| 1128 | if (t.char_code > 0x10ffff) { | 1169 | handle_string_escape(&t, (uint8_t)t.char_code); |
| 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 | } | | |
| 1164 | } | 1170 | } |
| 1165 | } | 1171 | } |
| 1166 | break; | 1172 | break; |
| ... | @@ -1409,6 +1415,7 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -1409,6 +1415,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1409 | tokenize_error(&t, "unterminated string"); | 1415 | tokenize_error(&t, "unterminated string"); |
| 1410 | break; | 1416 | break; |
| 1411 | case TokenizeStateStringEscape: | 1417 | case TokenizeStateStringEscape: |
| | 1418 | case TokenizeStateStringEscapeUnicodeStart: |
| 1412 | case TokenizeStateCharCode: | 1419 | case TokenizeStateCharCode: |
| 1413 | if (t.cur_tok->id == TokenIdStringLiteral) { | 1420 | if (t.cur_tok->id == TokenIdStringLiteral) { |
| 1414 | tokenize_error(&t, "unterminated string"); | 1421 | tokenize_error(&t, "unterminated string"); |