Skip to content

Commit 2ba2299

Browse files
Rosuavpfalcon
authored andcommitted
lexer, vstr: Add unicode support.
1 parent 1e3781b commit 2ba2299

2 files changed

Lines changed: 57 additions & 10 deletions

File tree

py/lexer.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -502,19 +502,32 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
502502
case 'v': c = 0x0b; break;
503503
case 'f': c = 0x0c; break;
504504
case 'r': c = 0x0d; break;
505+
case 'u':
506+
case 'U':
507+
if (is_bytes) {
508+
// b'\u1234' == b'\\u1234'
509+
vstr_add_char(&lex->vstr, '\\');
510+
break;
511+
}
512+
// Otherwise fall through.
505513
case 'x':
506514
{
507515
uint num = 0;
508-
if (!get_hex(lex, 2, &num)) {
516+
if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) {
509517
// TODO error message
510518
assert(0);
511519
}
512520
c = num;
513521
break;
514522
}
515-
case 'N': break; // TODO \N{name} only in strings
516-
case 'u': break; // TODO \uxxxx only in strings
517-
case 'U': break; // TODO \Uxxxxxxxx only in strings
523+
case 'N':
524+
// Supporting '\N{LATIN SMALL LETTER A}' == 'a' would require keeping the
525+
// entire Unicode name table in the core. As of Unicode 6.3.0, that's nearly
526+
// 3MB of text; even gzip-compressed and with minimal structure, it'll take
527+
// roughly half a meg of storage. This form of Unicode escape may be added
528+
// later on, but it's definitely not a priority right now. -- CJA 20140607
529+
assert(!"Unicode name escapes not supported");
530+
break;
518531
default:
519532
if (c >= '0' && c <= '7') {
520533
// Octal sequence, 1-3 chars
@@ -533,7 +546,13 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
533546
}
534547
}
535548
if (c != MP_LEXER_CHAR_EOF) {
536-
vstr_add_char(&lex->vstr, c);
549+
if (c < 0x110000 && !is_bytes) {
550+
vstr_add_char(&lex->vstr, c);
551+
} else if (c < 0x100 && is_bytes) {
552+
vstr_add_byte(&lex->vstr, c);
553+
} else {
554+
assert(!"TODO: Throw an error, invalid escape code probably");
555+
}
537556
}
538557
} else {
539558
vstr_add_char(&lex->vstr, CUR_CHAR(lex));

py/vstr.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,40 @@ void vstr_add_byte(vstr_t *vstr, byte b) {
199199
}
200200

201201
void vstr_add_char(vstr_t *vstr, unichar c) {
202-
// TODO UNICODE
203-
byte *buf = (byte*)vstr_add_len(vstr, 1);
204-
if (buf == NULL) {
205-
return;
202+
// TODO: Can this be simplified and deduplicated?
203+
// Is it worth just calling vstr_add_len(vstr, 4)?
204+
if (c < 0x80) {
205+
byte *buf = (byte*)vstr_add_len(vstr, 1);
206+
if (buf == NULL) {
207+
return;
208+
}
209+
*buf = (byte)c;
210+
} else if (c < 0x800) {
211+
byte *buf = (byte*)vstr_add_len(vstr, 2);
212+
if (buf == NULL) {
213+
return;
214+
}
215+
buf[0] = (c >> 6) | 0xC0;
216+
buf[1] = (c & 0x3F) | 0x80;
217+
} else if (c < 0x10000) {
218+
byte *buf = (byte*)vstr_add_len(vstr, 3);
219+
if (buf == NULL) {
220+
return;
221+
}
222+
buf[0] = (c >> 12) | 0xE0;
223+
buf[1] = ((c >> 6) & 0x3F) | 0x80;
224+
buf[2] = (c & 0x3F) | 0x80;
225+
} else {
226+
assert(c < 0x110000);
227+
byte *buf = (byte*)vstr_add_len(vstr, 4);
228+
if (buf == NULL) {
229+
return;
230+
}
231+
buf[0] = (c >> 18) | 0xF0;
232+
buf[1] = ((c >> 12) & 0x3F) | 0x80;
233+
buf[2] = ((c >> 6) & 0x3F) | 0x80;
234+
buf[3] = (c & 0x3F) | 0x80;
206235
}
207-
buf[0] = c;
208236
}
209237

210238
void vstr_add_str(vstr_t *vstr, const char *str) {

0 commit comments

Comments
 (0)