fspl/llvm/encode.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)) + `"`
}