func (re *RegExp) String() string {
	var b bytes.Buffer
	return re.toStringBuilder(&b).String()
}
Constructs string from parsed regular expression
package automaton
import (
	"bytes"
	"fmt"
	"strconv"
	"strings"
)
type Kind int
const (
	REGEXP_UNION         = Kind(1)
	REGEXP_CONCATENATION = Kind(2)
	REGEXP_INTERSECTION  = Kind(3)
	REGEXP_OPTIONAL      = Kind(4)
	REGEXP_REPEAT        = Kind(5)
	REGEXP_REPEAT_MIN    = Kind(6)
	REGEXP_REPEAT_MINMAX = Kind(7)
	REGEXP_COMPLEMENT    = Kind(8)
	REGEXP_CHAR          = Kind(9)
	REGEXP_CHAR_RANGE    = Kind(10)
	REGEXP_ANYCHAR       = Kind(11)
	REGEXP_EMPTY         = Kind(12)
	REGEXP_STRING        = Kind(13)
	REGEXP_ANYSTRING     = Kind(14)
	REGEXP_AUTOMATON     = Kind(15)
	REGEXP_INTERVAL      = Kind(16)
)
const (
	INTERSECTION = 0x0001  
	COMPLEMENT   = 0x0002  
	EMPTY        = 0x0004  
	ANYSTRING    = 0x0008  
	AUTOMATON    = 0x0010  
	INTERVAL     = 0x0020  
	ALL          = 0xffff  
	NONE         = 0x0000  
	allow_mutation = false
)
type RegExp struct {
	kind             Kind
	exp1, exp2       *RegExp
	s                string
	c                int
	min, max, digits int
	from, to         int
	b                []rune
	flags            int
	pos              int
}
func NewRegExp(s string) *RegExp {
	return NewRegExpWithFlag(s, ALL)
}
func NewRegExpWithFlag(s string, flags int) *RegExp {
	ans := &RegExp{
		b:     []rune(s),
		flags: flags,
	}
	var e *RegExp
	if len(s) == 0 {
		e = makeStringRE("")
	} else {
		e = ans.parseUnionExp()
		if ans.pos < len(ans.b) {
			panic(fmt.Sprintf("end-of-string expected at position %v", ans.pos))
		}
	}
	ans.kind = e.kind
	ans.exp1, ans.exp2 = e.exp1, e.exp2
	ans.s = e.s
	ans.c = e.c
	ans.min, ans.max, ans.digits = e.min, e.max, e.digits
	ans.from, ans.to = e.from, e.to
	ans.b = nil
	return ans
}
func (re *RegExp) ToAutomaton() *Automaton {
	return re.toAutomaton(nil, nil)
}
func (re *RegExp) toAutomaton(automata map[string]*Automaton,
	provider AutomatonProvider) *Automaton {
	var list []*Automaton
	var a *Automaton = nil
	switch re.kind {
	case REGEXP_UNION:
		list = make([]*Automaton, 0)
		list = re.findLeaves(re.exp1, REGEXP_UNION, list, automata, provider)
		list = re.findLeaves(re.exp2, REGEXP_UNION, list, automata, provider)
		a = unionN(list)
		a = minimize(a)
	case REGEXP_CONCATENATION:
		list = make([]*Automaton, 0)
		list = re.findLeaves(re.exp1, REGEXP_CONCATENATION, list, automata, provider)
		list = re.findLeaves(re.exp2, REGEXP_CONCATENATION, list, automata, provider)
		a = concatenateN(list)
		a = minimize(a)
	case REGEXP_INTERSECTION:
		a = intersection(re.exp1.toAutomaton(automata, provider),
			re.exp2.toAutomaton(automata, provider))
		a = minimize(a)
	case REGEXP_OPTIONAL:
		a = optional(re.exp1.toAutomaton(automata, provider))
		a = minimize(a)
	case REGEXP_REPEAT:
		a = repeat(re.exp1.toAutomaton(automata, provider))
		a = minimize(a)
	case REGEXP_REPEAT_MIN:
		a = repeatMin(re.exp1.toAutomaton(automata, provider), re.min)
		a = minimize(a)
	case REGEXP_REPEAT_MINMAX:
		panic("not implemented yet")
	case REGEXP_COMPLEMENT:
		a = complement(re.exp1.toAutomaton(automata, provider))
		a = minimize(a)
	case REGEXP_CHAR:
		a = makeChar(re.c)
	case REGEXP_CHAR_RANGE:
		a = makeCharRange(re.from, re.to)
	case REGEXP_ANYCHAR:
		a = makeAnyChar()
	case REGEXP_EMPTY:
		panic("not implemented yet")
	case REGEXP_STRING:
		a = makeString(re.s)
	case REGEXP_ANYSTRING:
		panic("not implemented yet")
	case REGEXP_AUTOMATON:
		panic("not implemented yet")
	case REGEXP_INTERVAL:
		panic("not implemented yet")
	}
	return a
}
func (re *RegExp) findLeaves(exp *RegExp, kind Kind, list []*Automaton,
	automata map[string]*Automaton, provider AutomatonProvider) []*Automaton {
	if exp.kind == kind {
		list = re.findLeaves(exp.exp1, kind, list, automata, provider)
		list = re.findLeaves(exp.exp2, kind, list, automata, provider)
		return list
	} else {
		return append(list, exp.toAutomaton(automata, provider))
	}
}