135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
package llvm
|
|
|
|
import "strings"
|
|
|
|
const (
|
|
// decimal specifies the decimal digit characters.
|
|
decimal = "0123456789"
|
|
// upper specifies the uppercase letters.
|
|
upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
// lower specifies the lowercase letters.
|
|
lower = "abcdefghijklmnopqrstuvwxyz"
|
|
// alpha specifies the alphabetic characters.
|
|
alpha = upper + lower
|
|
// head is the set of valid characters for the first character of an
|
|
// identifier.
|
|
head = alpha + "$-._"
|
|
// tail is the set of valid characters for the remaining characters of an
|
|
// identifier (i.e. all characters in the identifier except the first). All
|
|
// characters of a label may be from the tail set, even the first character.
|
|
tail = head + decimal
|
|
// quotedIdent is the set of valid characters in quoted identifiers, which
|
|
// excludes ASCII control characters, double quote, backslash and extended
|
|
// ASCII characters.
|
|
quotedIdent = " !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
)
|
|
|
|
func EscapeIdent (s string) string {
|
|
replace := false
|
|
extra := 0
|
|
for i := 0; i < len(s); i++ {
|
|
if strings.IndexByte(tail, s[i]) == -1 {
|
|
// Check if a replacement is required.
|
|
//
|
|
// Note, there are characters which are not valid in an identifier
|
|
// (e.g. '#') but are valid in a quoted identifier, and therefore
|
|
// require a replacement (i.e. quoted identifier), but no extra
|
|
// characters for the escape sequence.
|
|
replace = true
|
|
}
|
|
if strings.IndexByte(quotedIdent, s[i]) == -1 {
|
|
// Two extra bytes are required for each byte not valid in a quoted
|
|
// identifier; e.g.
|
|
//
|
|
// "\t" -> `\09`
|
|
// "世" -> `\E4\B8\96`
|
|
extra += 2
|
|
}
|
|
}
|
|
if !replace {
|
|
return s
|
|
}
|
|
// Replace invalid characters.
|
|
const hextable = "0123456789ABCDEF"
|
|
buf := make([]byte, len(s)+extra)
|
|
j := 0
|
|
for i := 0; i < len(s); i++ {
|
|
b := s[i]
|
|
if strings.IndexByte(quotedIdent, b) != -1 {
|
|
buf[j] = b
|
|
j++
|
|
continue
|
|
}
|
|
buf[j] = '\\'
|
|
buf[j+1] = hextable[b>>4]
|
|
buf[j+2] = hextable[b&0x0F]
|
|
j += 3
|
|
}
|
|
// Add surrounding quotes.
|
|
return `"` + string(buf) + `"`
|
|
}
|
|
|
|
func Escape (s []byte, valid func(b byte) bool) string {
|
|
// Check if a replacement is required.
|
|
extra := 0
|
|
for i := 0; i < len(s); i++ {
|
|
if !valid(s[i]) {
|
|
// Two extra bytes are required for each invalid byte; e.g.
|
|
// "#" -> `\23`
|
|
// "世" -> `\E4\B8\96`
|
|
extra += 2
|
|
}
|
|
}
|
|
if extra == 0 {
|
|
return string(s)
|
|
}
|
|
// Replace invalid characters.
|
|
const hextable = "0123456789ABCDEF"
|
|
buf := make([]byte, len(s)+extra)
|
|
j := 0
|
|
for i := 0; i < len(s); i++ {
|
|
b := s[i]
|
|
if valid(b) {
|
|
buf[j] = b
|
|
j++
|
|
continue
|
|
}
|
|
buf[j] = '\\'
|
|
buf[j+1] = hextable[b>>4]
|
|
buf[j+2] = hextable[b&0x0F]
|
|
j += 3
|
|
}
|
|
return string(buf)
|
|
}
|
|
|
|
func EscapeString (s []byte) string {
|
|
valid := func(b byte) bool {
|
|
return ' ' <= b && b <= '~' && b != '"' && b != '\\'
|
|
}
|
|
return string(Escape(s, valid))
|
|
}
|
|
|
|
func EncodeTypeName (name string) string {
|
|
return "%" + EscapeIdent(name)
|
|
}
|
|
|
|
func EncodeRegisterName (name string) string {
|
|
return "%" + EscapeIdent(name)
|
|
}
|
|
|
|
func EncodeGlobalName (name string) string {
|
|
return "@" + EscapeIdent(name)
|
|
}
|
|
|
|
func EncodeFunctionName (name string) string {
|
|
return EncodeGlobalName(name)
|
|
}
|
|
|
|
func EncodeLabelName (name string) string {
|
|
return EscapeIdent(name) + ":"
|
|
}
|
|
|
|
func EscapeQuoteString (s []byte) string {
|
|
return `"` + string(EscapeString(s)) + `"`
|
|
}
|