func splitAndUnescape(text string) []string {
	var start int
	var result []string
	for _, m := range splitPattern.FindAllStringIndex(text, -1) {
		result = append(result, replaceEscapes(text[start:m[1]-1]))
		start = m[1]
	}
	return append(result, replaceEscapes(text[start:len(text)]))
}
splitAndUnescape splits the provided text on non-escaped semi-colons and replaces escape sequences.
package ast
import (
	"fmt"
	"regexp"
	"strings"
)
var (
	escapePattern = regexp.MustCompile(`\\.`)
	splitPattern  = regexp.MustCompile(`^;|[^\\];`)
)
func (a *ArgumentList) Eval(vars Bindings) []string {
	var values []string
	for _, arg := range a.Values {
		values = append(values, arg.Eval(vars)...)
	}
	return values
}
func (a *Argument) Eval(vars Bindings) []string {
	switch {
	case a.QuotedArgument != nil:
		return a.QuotedArgument.Eval(vars)
	case a.UnquotedArgument != nil:
		return a.UnquotedArgument.Eval(vars)
	case a.BracketArgument != nil:
		return a.BracketArgument.Eval(vars)
	case a.ArgumentList != nil:
		values := []string{"("}
		values = append(values, a.ArgumentList.Eval(vars)...)
		return append(values, ")")
	}
	panic("Missing concrete argument!")
}
func (a *QuotedArgument) Eval(vars Bindings) []string {
	var parts []string
	for _, e := range a.Elements {
		parts = append(parts, e.Eval(vars)...)
	}
	return []string{replaceEscapes(strings.Join(parts, ""))}
}
func (e *QuotedElement) Eval(vars Bindings) []string {
	if e.Ref != nil {
		return e.Ref.Eval(vars)
	}
	return []string{e.Text}
}
func (a *UnquotedArgument) Eval(vars Bindings) []string {
	var parts []string
	for _, e := range a.Elements {
		parts = append(parts, e.Eval(vars)...)
	}
	return splitAndUnescape(strings.Join(parts, ""))
}
func (e *UnquotedElement) Eval(vars Bindings) []string {
	if e.Ref != nil {
		return e.Ref.Eval(vars)
	}
	return []string{e.Text}
}
func (a *BracketArgument) Eval(vars Bindings) []string {
	return []string{a.Text}
}
func (v *VariableReference) Eval(vars Bindings) []string {
	var name []string
	for _, e := range v.Elements {
		name = append(name, e.Eval(vars)...)
	}
	var get func(string) string
	switch v.Domain {
	case DomainDefault:
		get = vars.Get
	case DomainCache:
		get = vars.GetCache
	case DomainEnv:
		get = vars.GetEnv
	case DomainMake:
		fallthrough
	default:
		panic(fmt.Sprintf("unrecognized domain: %#v", v.Domain))
	}
	return []string{get(strings.Join(name, ""))}
}
func (v *VariableElement) Eval(vars Bindings) []string {
	parts := []string{v.Text}
	if v.Ref != nil {
		for _, p := range v.Ref.Eval(vars) {
			parts = append(parts, p)
		}
	}
	return []string{strings.Join(parts, "")}
}
func replaceEscapes(text string) string {
	return escapePattern.ReplaceAllStringFunc(text, func(m string) string {
		switch m[1] {
		case 'n':
			return "\n"
		case 'r':
			return "\r"
		case 't':
			return "\t"
		default:
			return m[1:]
		}
	})
}