func (h *HexString) WriteSource(w io.Writer) (err error) {
	if _, err = io.WriteString(w, fmt.Sprintf("$%s", h.Identifier)); err != nil {
		return err
	}
	if _, err = io.WriteString(w, " = { "); err != nil {
		return err
	}
	if err = h.Tokens.WriteSource(w); err != nil {
		return err
	}
	if _, err = io.WriteString(w, "}"); err != nil {
		return err
	}
	if h.Private {
		_, err = io.WriteString(w, " private")
	}
	return err
}
WriteSource writes the node's source into the writer w.
package ast
import (
	"fmt"
	"io"
	"strconv"
	"strings"
	"github.com/VirusTotal/gyp/pb"
	"github.com/golang/protobuf/proto"
)
const (
	lowerhex = "0123456789abcdef"
)
func Escape(s string) string {
	ascii := make([]byte, 0, len(s))
	for i := 0; i < len(s); i++ {
		switch {
		case s[i] == '\n':
			ascii = append(ascii, `\n`...)
		case s[i] == '\r':
			ascii = append(ascii, `\r`...)
		case s[i] == '\t':
			ascii = append(ascii, `\t`...)
		case s[i] == '\\':
			ascii = append(ascii, `\\`...)
		case s[i] == '"':
			ascii = append(ascii, `\"`...)
		case s[i] >= 32 && s[i] < 127:
			ascii = append(ascii, s[i])
		default:
			ascii = append(ascii, `\x`...)
			ascii = append(ascii, lowerhex[s[i]>>4])
			ascii = append(ascii, lowerhex[s[i]&0xF])
		}
	}
	return string(ascii)
}
// String is the interface implemented by the different types of strings that
// are supported by YARA (i.e: text strings, hex strings and regexps).
type String interface {
	fmt.Stringer
	AsProto() *pb.String
	GetIdentifier() string
	GetLineNo() int
}
// BaseString is a structure that contains the fields that are common to all
// types of strings. This structure is embedded in TextString, HexString and
// RegexpString.
type BaseString struct {
	// Identifier for the string, without the $ prefix.
	Identifier string
	// Line number where the string was defined.
	LineNo int
}
// TextString describes a YARA text string.
type TextString struct {
	BaseString
	// Value contains the string exactly as it appears in the YARA rule. Escape
	// sequences remain escaped. See the UnescapedValue function.
	Value          string
	ASCII          bool
	Wide           bool
	Nocase         bool
	Fullword       bool
	Private        bool
	Base64         bool
	Base64Wide     bool
	Base64Alphabet string
	Xor            bool
	XorMin         int32
	XorMax         int32
}
// RegexpString describes a YARA regexp.
type RegexpString struct {
	BaseString
	// Value contains the string exactly as it appears in the YARA rule. Escape
	// sequences remain escaped. See the UnescapeValue function.
	Regexp   *LiteralRegexp
	ASCII    bool
	Wide     bool
	Nocase   bool
	Fullword bool
	Private  bool
}
// HexString describes a YARA hex string. Hex strings have an identifier and
// a sequence of tokens that conform the abstract syntax tree for the hex
// string. Each token can be any of the following types:
//   HexBytes: Represents a sequence of bytes, possibly masked, like:
//      01 02 03,  34 ?? A1 F? 03 ?3
//   HexJump: Represents a jump in the hex string, like:
//      [21], [0-100]
//   HexOr: Represents an alternative, like:
//      (A|B), (A|B|C)
//
type HexString struct {
	BaseString
	Tokens  HexTokens
	Private bool
}
// HexToken is the interface implemented by all types of token
type HexToken interface {
	Node
}
// HexTokens is a sequence of tokens.
type HexTokens []HexToken
// HexJump is an HexToken that represents a jump in the hex string, like for
// example the [10-20] jump in {01 02 [10-20] 03 04}. If End is 0, it means
// infinite, the jump [20-] has Start=20 and End=0.
type HexJump struct {
	Start int
	End   int
}
// HexBytes is an HexToken that represents a byte sequence. The bytes are
// stored in Bytes, while Masks contains a nibble-wise mask for each of the
// bytes (both arrays have the same length). Possible masks are:
// 00 -> Full wildcard, the corresponding byte is ignored (??).
// 0F -> The higher nibble is ignored (?X)
// F0 -> The lower nibble is ignored (X?)
// FF -> No wildcard at all.
type HexBytes struct {
	Bytes []byte
	Masks []byte
}
// HexOr is an HexToken that represents an alternative in the hex string, like
// the (03 04 | 05 06) alternative in { 01 02 (03 04 | 05 06) 07 08 }. Each
// item in Alternatives corresponds to an alternative.
type HexOr struct {
	Alternatives HexTokens
}
// UnescapedValue returns the string's Value with any escape sequence replaced
// by the actual character that it represents.
func (t *TextString) UnescapedValue() string {
	unescaped, err := strconv.Unquote(fmt.Sprintf(`"%s"`, t.Value))
	if err != nil {
		panic(err)
	}
	return unescaped
}
// Children returns the Node's children.
func (h *HexJump) Children() []Node {
	return []Node{}
}
// Children returns the Node's children.
func (h *HexBytes) Children() []Node {
	return []Node{}
}
// Children returns the Node's children.
func (h HexTokens) Children() []Node {
	return []Node{}
}
// Children returns the Node's children.
func (h *HexOr) Children() []Node {
	nodes := make([]Node, len(h.Alternatives))
	for i, a := range h.Alternatives {
		nodes[i] = a
	}
	return nodes
}
func (s *BaseString) GetIdentifier() string {
	return s.Identifier
}
func (s *BaseString) GetLineNo() int {
	return s.LineNo
}
func (t *TextString) String() string {
	var b strings.Builder
	t.WriteSource(&b)
	return b.String()
}
func (r *RegexpString) String() string {
	var b strings.Builder
	r.WriteSource(&b)
	return b.String()
}
func (h *HexString) String() string {
	var b strings.Builder
	h.WriteSource(&b)
	return b.String()
}
// WriteSource writes the node's source into the writer w.
func (t *TextString) WriteSource(w io.Writer) error {
	_, err := io.WriteString(w, fmt.Sprintf("$%s", t.Identifier))
	if err == nil {
		_, err = io.WriteString(w, " = ")
	}
	if err == nil {
		_, err = io.WriteString(w, fmt.Sprintf(`"%s"`, t.Value))
	}
	if err == nil && t.ASCII {
		_, err = io.WriteString(w, " ascii")
	}
	if err == nil && t.Wide {
		_, err = io.WriteString(w, " wide")
	}
	if err == nil && t.Nocase {
		_, err = io.WriteString(w, " nocase")
	}
	if err == nil && t.Fullword {
		_, err = io.WriteString(w, " fullword")
	}
	if err == nil && t.Private {
		_, err = io.WriteString(w, " private")
	}
	if err == nil && t.Base64 {
		if _, err = io.WriteString(w, " base64"); err == nil && t.Base64Alphabet != "" {
			_, err = io.WriteString(w, fmt.Sprintf("(\"%s\")", t.Base64Alphabet))
		}
	}
	if err == nil && t.Base64Wide {
		if _, err = io.WriteString(w, " base64wide"); err == nil && t.Base64Alphabet != "" {
			_, err = io.WriteString(w, fmt.Sprintf("(\"%s\")", t.Base64Alphabet))
		}
	}
	if err == nil && t.Xor {
		if t.XorMin == 0 && t.XorMax == 255 {
			_, err = io.WriteString(w, " xor")
		} else if t.XorMin == t.XorMax {
			_, err = io.WriteString(w, fmt.Sprintf(" xor(%d)", t.XorMin))
		} else {
			_, err = io.WriteString(w, fmt.Sprintf(" xor(%d-%d)", t.XorMin, t.XorMax))
		}
	}
	return err
}
func (r *RegexpString) WriteSource(w io.Writer) (err error) {
	if _, err = io.WriteString(w, fmt.Sprintf("$%s", r.Identifier)); err != nil {
		return err
	}
	if _, err = io.WriteString(w, " = "); err != nil {
		return err
	}
	if err = r.Regexp.WriteSource(w); err != nil {
		return err
	}
	if r.ASCII {
		if _, err = io.WriteString(w, " ascii"); err != nil {
			return err
		}
	}
	if r.Wide {
		if _, err = io.WriteString(w, " wide"); err != nil {
			return err
		}
	}
	if r.Nocase {
		if _, err = io.WriteString(w, " nocase"); err != nil {
			return err
		}
	}
	if r.Fullword {
		if _, err = io.WriteString(w, " fullword"); err != nil {
			return err
		}
	}
	if r.Private {
		_, err = io.WriteString(w, " private")
	}
	return err
}