reflect: add sipmlified strconv.Quote() implementation for struct tags
Этот коммит содержится в:
родитель
195de23d3b
коммит
5faff2e13a
3 изменённых файлов: 101 добавлений и 6 удалений
|
@ -188,7 +188,6 @@ var typeTests = []pair{
|
||||||
}{},
|
}{},
|
||||||
"struct { a int8; b int8; c int8; d int8; e int8; f int32 }",
|
"struct { a int8; b int8; c int8; d int8; e int8; f int32 }",
|
||||||
},
|
},
|
||||||
/* // TODO(tinygo): Reflects tags aren't properly quoted
|
|
||||||
{struct {
|
{struct {
|
||||||
x struct {
|
x struct {
|
||||||
a int8 `reflect:"hi there"`
|
a int8 `reflect:"hi there"`
|
||||||
|
@ -203,6 +202,7 @@ var typeTests = []pair{
|
||||||
}{},
|
}{},
|
||||||
`struct { a int8 "reflect:\"hi \\x00there\\t\\n\\\"\\\\\"" }`,
|
`struct { a int8 "reflect:\"hi \\x00there\\t\\n\\\"\\\\\"" }`,
|
||||||
},
|
},
|
||||||
|
/* // TODO(tinygo): Functions not supported
|
||||||
{struct {
|
{struct {
|
||||||
x struct {
|
x struct {
|
||||||
f func(args ...int)
|
f func(args ...int)
|
||||||
|
|
|
@ -30,6 +30,10 @@ func unhex(b byte) (v rune, ok bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
lowerhex = "0123456789abcef"
|
||||||
|
)
|
||||||
|
|
||||||
// unquoteChar decodes the first character or byte in the escaped string
|
// unquoteChar decodes the first character or byte in the escaped string
|
||||||
// or character literal represented by the string s.
|
// or character literal represented by the string s.
|
||||||
// It returns four values:
|
// It returns four values:
|
||||||
|
@ -231,6 +235,101 @@ func unquote(s string) (string, error) {
|
||||||
return string(buf), nil
|
return string(buf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func quote(s string) string {
|
||||||
|
buf := make([]byte, 0, 3*len(s)/2)
|
||||||
|
const quote = '"'
|
||||||
|
|
||||||
|
buf = append(buf, quote)
|
||||||
|
for width := 0; len(s) > 0; s = s[width:] {
|
||||||
|
r := rune(s[0])
|
||||||
|
width = 1
|
||||||
|
if r >= utf8.RuneSelf {
|
||||||
|
r, width = utf8.DecodeRuneInString(s)
|
||||||
|
}
|
||||||
|
if width == 1 && r == utf8.RuneError {
|
||||||
|
buf = append(buf, `\x`...)
|
||||||
|
buf = append(buf, lowerhex[s[0]>>4])
|
||||||
|
buf = append(buf, lowerhex[s[0]&0xF])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf = appendEscapedRune(buf, r)
|
||||||
|
}
|
||||||
|
buf = append(buf, quote)
|
||||||
|
return string(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEscapedRune(buf []byte, r rune) []byte {
|
||||||
|
|
||||||
|
const quote = '"'
|
||||||
|
|
||||||
|
var runeTmp [utf8.UTFMax]byte
|
||||||
|
if r == rune(quote) || r == '\\' { // always backslashed
|
||||||
|
buf = append(buf, '\\')
|
||||||
|
buf = append(buf, byte(r))
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
if isPrint(r) {
|
||||||
|
n := utf8.EncodeRune(runeTmp[:], r)
|
||||||
|
buf = append(buf, runeTmp[:n]...)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case '\a':
|
||||||
|
buf = append(buf, `\a`...)
|
||||||
|
case '\b':
|
||||||
|
buf = append(buf, `\b`...)
|
||||||
|
case '\f':
|
||||||
|
buf = append(buf, `\f`...)
|
||||||
|
case '\n':
|
||||||
|
buf = append(buf, `\n`...)
|
||||||
|
case '\r':
|
||||||
|
buf = append(buf, `\r`...)
|
||||||
|
case '\t':
|
||||||
|
buf = append(buf, `\t`...)
|
||||||
|
case '\v':
|
||||||
|
buf = append(buf, `\v`...)
|
||||||
|
default:
|
||||||
|
switch {
|
||||||
|
case r < ' ' || r == 0x7f:
|
||||||
|
buf = append(buf, `\x`...)
|
||||||
|
buf = append(buf, lowerhex[byte(r)>>4])
|
||||||
|
buf = append(buf, lowerhex[byte(r)&0xF])
|
||||||
|
case !utf8.ValidRune(r):
|
||||||
|
r = 0xFFFD
|
||||||
|
fallthrough
|
||||||
|
case r < 0x10000:
|
||||||
|
buf = append(buf, `\u`...)
|
||||||
|
for s := 12; s >= 0; s -= 4 {
|
||||||
|
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
buf = append(buf, `\U`...)
|
||||||
|
for s := 28; s >= 0; s -= 4 {
|
||||||
|
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is only used for struct tags. Assume
|
||||||
|
func isPrint(r rune) bool {
|
||||||
|
if r <= 0xFF {
|
||||||
|
if 0x20 <= r && r <= 0x7E {
|
||||||
|
// All the ASCII is printable from space through DEL-1.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if 0xA1 <= r && r <= 0xFF {
|
||||||
|
// Similarly for ¡ through ÿ...
|
||||||
|
return r != 0xAD // ...except for the bizarre soft hyphen.
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// TinyGo: Skip all other unicode processing
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// contains reports whether the string contains the byte c.
|
// contains reports whether the string contains the byte c.
|
||||||
func contains(s string, c byte) bool {
|
func contains(s string, c byte) bool {
|
||||||
return indexByteString(s, c) != -1
|
return indexByteString(s, c) != -1
|
||||||
|
|
|
@ -554,11 +554,7 @@ func (t *rawType) String() string {
|
||||||
f := t.rawField(i)
|
f := t.rawField(i)
|
||||||
s += " " + f.Name + " " + f.Type.String()
|
s += " " + f.Name + " " + f.Type.String()
|
||||||
if f.Tag != "" {
|
if f.Tag != "" {
|
||||||
// TODO(dgryski): The tag should be
|
s += " " + quote(string(f.Tag))
|
||||||
// double-quoted and escaped; that requires
|
|
||||||
// strconv and reflectlite or our own Quote()
|
|
||||||
// implementation
|
|
||||||
s += " " + string(f.Tag)
|
|
||||||
}
|
}
|
||||||
// every field except the last needs a semicolon
|
// every field except the last needs a semicolon
|
||||||
if i < numField-1 {
|
if i < numField-1 {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче