authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-08 17:30:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-08 17:30:26-07:00
log73c814e5c0c4a5747333dfb4d8ef2fb7248a1878
tree98c9a8c148178662a7d359ce0e569db3c0552161
parent491e3cb5c5e21477f9f45b25825e27905685760c

support hex escapes in string literals


2 files changed, 117 insertions(+), 34 deletions(-)

src/parser.cpp+111-34
...@@ -223,6 +223,42 @@ static uint8_t parse_char_literal(ParseContext *pc, Token *token) {...@@ -223,6 +223,42 @@ static uint8_t parse_char_literal(ParseContext *pc, Token *token) {
223 return return_value;223 return return_value;
224}224}
225225
226static int get_hex_digit(uint8_t c) {
227 switch (c) {
228 case '0': return 0;
229 case '1': return 1;
230 case '2': return 2;
231 case '3': return 3;
232 case '4': return 4;
233 case '5': return 5;
234 case '6': return 6;
235 case '7': return 7;
236 case '8': return 8;
237 case '9': return 9;
238
239 case 'a':
240 case 'A':
241 return 10;
242 case 'b':
243 case 'B':
244 return 11;
245 case 'c':
246 case 'C':
247 return 12;
248 case 'd':
249 case 'D':
250 return 13;
251 case 'e':
252 case 'E':
253 return 14;
254 case 'f':
255 case 'F':
256 return 15;
257 default:
258 return -1;
259 }
260}
261
226static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str,262static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str,
227 ZigList<SrcPos> *offset_map)263 ZigList<SrcPos> *offset_map)
228{264{
...@@ -240,12 +276,22 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool...@@ -240,12 +276,22 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool
240 // convert escape sequences276 // convert escape sequences
241 // detect c string literal277 // detect c string literal
242278
279 enum State {
280 StateStart,
281 StateEscape,
282 StateHex1,
283 StateHex2,
284 };
285
243 buf_resize(buf, 0);286 buf_resize(buf, 0);
244 bool escape = false;287
288 State state = StateStart;
245 bool skip_quote;289 bool skip_quote;
246 SrcPos pos = {token->start_line, token->start_column};290 SrcPos pos = {token->start_line, token->start_column};
291 int hex_value = 0;
247 for (int i = token->start_pos; i < token->end_pos - 1; i += 1) {292 for (int i = token->start_pos; i < token->end_pos - 1; i += 1) {
248 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);293 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
294
249 if (i == token->start_pos) {295 if (i == token->start_pos) {
250 skip_quote = (c == 'c');296 skip_quote = (c == 'c');
251 if (out_c_str) {297 if (out_c_str) {
...@@ -256,41 +302,72 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool...@@ -256,41 +302,72 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool
256 } else if (skip_quote) {302 } else if (skip_quote) {
257 skip_quote = false;303 skip_quote = false;
258 } else {304 } else {
259 if (escape) {305 switch (state) {
260 switch (c) {306 case StateStart:
261 case '\\':307 if (c == '\\') {
262 buf_append_char(buf, '\\');308 state = StateEscape;
263 if (offset_map) offset_map->append(pos);309 } else {
264 break;310 buf_append_char(buf, c);
265 case 'r':
266 buf_append_char(buf, '\r');
267 if (offset_map) offset_map->append(pos);
268 break;
269 case 'n':
270 buf_append_char(buf, '\n');
271 if (offset_map) offset_map->append(pos);
272 break;
273 case 't':
274 buf_append_char(buf, '\t');
275 if (offset_map) offset_map->append(pos);
276 break;
277 case '"':
278 buf_append_char(buf, '"');
279 if (offset_map) offset_map->append(pos);311 if (offset_map) offset_map->append(pos);
312 }
313 break;
314 case StateEscape:
315 switch (c) {
316 case '\\':
317 buf_append_char(buf, '\\');
318 if (offset_map) offset_map->append(pos);
319 state = StateStart;
320 break;
321 case 'r':
322 buf_append_char(buf, '\r');
323 if (offset_map) offset_map->append(pos);
324 state = StateStart;
325 break;
326 case 'n':
327 buf_append_char(buf, '\n');
328 if (offset_map) offset_map->append(pos);
329 state = StateStart;
330 break;
331 case 't':
332 buf_append_char(buf, '\t');
333 if (offset_map) offset_map->append(pos);
334 state = StateStart;
335 break;
336 case '"':
337 buf_append_char(buf, '"');
338 if (offset_map) offset_map->append(pos);
339 state = StateStart;
340 break;
341 case 'x':
342 state = StateHex1;
343 break;
344 default:
345 ast_error(pc, token, "invalid escape character");
346 break;
347 }
348 break;
349 case StateHex1:
350 {
351 int hex_digit = get_hex_digit(c);
352 if (hex_digit == -1) {
353 ast_error(pc, token, "invalid hex digit: '%c'", c);
354 }
355 hex_value = hex_digit * 16;
356 state = StateHex2;
280 break;357 break;
281 case 'x':358 }
282 zig_panic("TODO");359 case StateHex2:
283 break;360 {
284 default:361 int hex_digit = get_hex_digit(c);
285 ast_error(pc, token, "invalid escape character");362 if (hex_digit == -1) {
363 ast_error(pc, token, "invalid hex digit: '%c'", c);
364 }
365 hex_value += hex_digit;
366 assert(hex_value >= 0 && hex_value <= 255);
367 buf_append_char(buf, hex_value);
368 state = StateStart;
286 break;369 break;
287 }370 }
288 escape = false;
289 } else if (c == '\\') {
290 escape = true;
291 } else {
292 buf_append_char(buf, c);
293 if (offset_map) offset_map->append(pos);
294 }371 }
295 }372 }
296 if (c == '\n') {373 if (c == '\n') {
...@@ -300,7 +377,7 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool...@@ -300,7 +377,7 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool
300 pos.column += 1;377 pos.column += 1;
301 }378 }
302 }379 }
303 assert(!escape);380 assert(state == StateStart);
304 if (offset_map) offset_map->append(pos);381 if (offset_map) offset_map->append(pos);
305}382}
306383
test/self_hosted.zig+6
...@@ -560,3 +560,9 @@ fn call_fn_with_empty_string() {...@@ -560,3 +560,9 @@ fn call_fn_with_empty_string() {
560}560}
561561
562fn accepts_string(foo: []u8) { }562fn accepts_string(foo: []u8) { }
563
564
565#attribute("test")
566fn hex_escape() {
567 assert(str_eql("\x68\x65\x6c\x6c\x6f", "hello"));
568}