|
@@ -62,25 +62,25 @@ write_bytes :: proc(b: ^Builder, x: []byte) {
|
|
|
}
|
|
|
|
|
|
|
|
|
-write_encoded_rune :: proc(b: ^Builder, r: rune) {
|
|
|
- write_byte(b, '\'');
|
|
|
+write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) {
|
|
|
+ if write_quote do write_byte(b, '\'');
|
|
|
switch r {
|
|
|
- case '\a': write_string(b, "\\a");
|
|
|
- case '\b': write_string(b, "\\b");
|
|
|
- case '\e': write_string(b, "\\e");
|
|
|
- case '\f': write_string(b, "\\f");
|
|
|
- case '\n': write_string(b, "\\n");
|
|
|
- case '\r': write_string(b, "\\r");
|
|
|
- case '\t': write_string(b, "\\t");
|
|
|
- case '\v': write_string(b, "\\v");
|
|
|
+ case '\a': write_string(b, `\a"`);
|
|
|
+ case '\b': write_string(b, `\b"`);
|
|
|
+ case '\e': write_string(b, `\e"`);
|
|
|
+ case '\f': write_string(b, `\f"`);
|
|
|
+ case '\n': write_string(b, `\n"`);
|
|
|
+ case '\r': write_string(b, `\r"`);
|
|
|
+ case '\t': write_string(b, `\t"`);
|
|
|
+ case '\v': write_string(b, `\v"`);
|
|
|
case:
|
|
|
if r < 32 {
|
|
|
- write_string(b, "\\x");
|
|
|
+ write_string(b, `\x`);
|
|
|
buf: [2]byte;
|
|
|
s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil);
|
|
|
switch len(s) {
|
|
|
case 0: write_string(b, "00");
|
|
|
- case 1: write_rune(b, '0');
|
|
|
+ case 1: write_byte(b, '0');
|
|
|
case 2: write_string(b, s);
|
|
|
}
|
|
|
} else {
|
|
@@ -88,7 +88,69 @@ write_encoded_rune :: proc(b: ^Builder, r: rune) {
|
|
|
}
|
|
|
|
|
|
}
|
|
|
- write_byte(b, '\'');
|
|
|
+ if write_quote do write_byte(b, '\'');
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte) {
|
|
|
+ static DIGITS_LOWER := "0123456789abcdefx";
|
|
|
+
|
|
|
+ is_printable :: proc(r: rune) -> bool {
|
|
|
+ if r <= 0xff {
|
|
|
+ switch r {
|
|
|
+ case 0x20..0x7e:
|
|
|
+ return true;
|
|
|
+ case 0xa1..0xff: // ¡ through ÿ except for the soft hyphen
|
|
|
+ return r != 0xad; //
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO(bill): A proper unicode library will be needed!
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if r == rune(quote) || r == '\\' {
|
|
|
+ write_byte(b, '\\');
|
|
|
+ write_byte(b, byte(r));
|
|
|
+ return;
|
|
|
+ } else if is_printable(r) {
|
|
|
+ write_encoded_rune(b, r, false);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ switch r {
|
|
|
+ case '\a': write_string(b, `\a`);
|
|
|
+ case '\b': write_string(b, `\b`);
|
|
|
+ case '\e': write_string(b, `\e`);
|
|
|
+ case '\f': write_string(b, `\f`);
|
|
|
+ case '\n': write_string(b, `\n`);
|
|
|
+ case '\r': write_string(b, `\r`);
|
|
|
+ case '\t': write_string(b, `\t`);
|
|
|
+ case '\v': write_string(b, `\v`);
|
|
|
+ case:
|
|
|
+ switch {
|
|
|
+ case r < ' ':
|
|
|
+ write_byte(b, '\\');
|
|
|
+ write_byte(b, 'x');
|
|
|
+ write_byte(b, DIGITS_LOWER[byte(r)>>4]);
|
|
|
+ write_byte(b, DIGITS_LOWER[byte(r)&0xf]);
|
|
|
+
|
|
|
+ case r > utf8.MAX_RUNE:
|
|
|
+ r = 0xfffd;
|
|
|
+ fallthrough;
|
|
|
+ case r < 0x10000:
|
|
|
+ write_byte(b, '\\');
|
|
|
+ write_byte(b, 'u');
|
|
|
+ for s := 12; s >= 0; s -= 4 {
|
|
|
+ write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
|
|
|
+ }
|
|
|
+ case:
|
|
|
+ write_byte(b, '\\');
|
|
|
+ write_byte(b, 'U');
|
|
|
+ for s := 28; s >= 0; s -= 4 {
|
|
|
+ write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|