-
Notifications
You must be signed in to change notification settings - Fork 0
/
charmedEscape.go
83 lines (77 loc) · 1.85 KB
/
charmedEscape.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package charmed
import (
"fmt"
"unicode/utf8"
"github.com/ionous/tell/charm"
"github.com/ionous/tell/runes"
)
// starting after a backslash, read an escape encoded rune.
// the subsequent rune will return unhandled.
// \xFF, \uFFFF, \UffffFFFF
func decodeEscape(w runes.RuneWriter) charm.State {
return charm.Statement("decodeEscape", func(q rune) (ret charm.State) {
if totalWidth := hexEncodings[q]; totalWidth > 0 {
var v rune // build this up over multiple steps
width := totalWidth
ret = charm.Self("captureEscape", func(self charm.State, q rune) (ret charm.State) {
if x, ok := unhex(q); !ok {
e := fmt.Errorf("expected %d hex values", totalWidth)
ret = charm.Error(e)
} else {
v = v<<4 | x
if width = width - 1; width > 0 {
ret = self // not done, keep going.
} else {
if !utf8.ValidRune(v) {
ret = charm.Error(charm.InvalidRune(v))
} else {
w.WriteRune(v)
ret = charm.UnhandledNext()
}
}
}
return
})
} else {
// single replacement escapes:
if v, ok := escapes[q]; !ok {
e := fmt.Errorf("%w is not recognized after a backslash", charm.InvalidRune(q))
ret = charm.Error(e)
} else {
w.WriteRune(v)
ret = charm.UnhandledNext()
}
}
return
})
}
// from strconv/quote.go - by the go authors under a bsd-style license.
func unhex(c rune) (v rune, ok bool) {
switch {
case '0' <= c && c <= '9':
return c - '0', true
case 'a' <= c && c <= 'f':
return c - 'a' + 10, true
case 'A' <= c && c <= 'F':
return c - 'A' + 10, true
}
return
}
// value encoded escapes
var hexEncodings = map[rune]int{
'x': 2, // '\x80'
'u': 4, // '\ue000'
'U': 8, // ex. '\U0010ffff'
}
// standard escapes
var escapes = map[rune]rune{
'a': '\a',
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
'v': '\v',
'\\': '\\',
'"': '"',
}