demangle.go
func (st *state) substitution(forPrefix bool) AST {
	st.checkChar('S')
	if len(st.str) == 0 {
		st.fail("missing substitution index")
	}
	c := st.str[0]
	st.advance(1)
	dec := 1
	if c == '_' || isDigit(c) || isUpper(c) {
		id := 0
		if c != '_' {
			for c != '_' {
				// Don't overflow a 32-bit int.
				if id >= 0x80000000/36-36 {
					st.fail("substitution index overflow")
				}
				if isDigit(c) {
					id = id*36 + int(c-'0')
				} else if isUpper(c) {
					id = id*36 + int(c-'A') + 10
				} else {
					st.fail("invalid character in substitution index")
				}

				if len(st.str) == 0 {
					st.fail("missing end to substitution index")
				}
				c = st.str[0]
				st.advance(1)
				dec++
			}
			id++
		}

		if id >= len(st.subs) {
			st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), dec)
		}

		ret := st.subs[id]

		// We need to update any references to template
		// parameters to refer to the currently active
		// template.
		copy := func(a AST) AST {
			tp, ok := a.(*TemplateParam)
			if !ok {
				return nil
			}
			if len(st.templates) == 0 {
				st.failEarlier("substituted template parameter not in scope of template", dec)
			}
			template := st.templates[len(st.templates)-1]
			if template == nil {
				// This template parameter is within
				// the scope of a cast operator.
				return &TemplateParam{Index: tp.Index, Template: nil}
			}

			if tp.Index >= len(template.Args) {
				st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", tp.Index, len(template.Args)), dec)
			}

			return &TemplateParam{Index: tp.Index, Template: template}
		}
		var seen []AST
		skip := func(a AST) bool {
			if _, ok := a.(*Typed); ok {
				return true
			}
			for _, v := range seen {
				if v == a {
					return true
				}
			}
			seen = append(seen, a)
			return false
		}
		if c := ret.Copy(copy, skip); c != nil {
			return c
		}

		return ret
	} else {
		m := subAST
		if st.verbose {
			m = verboseAST
		}
		// For compatibility with the standard demangler, use
		// a longer name for a constructor or destructor.
		if forPrefix && len(st.str) > 0 && (st.str[0] == 'C' || st.str[0] == 'D') {
			m = verboseAST
		}
		a, ok := m[c]
		if !ok {
			st.failEarlier("unrecognized substitution code", 1)
		}

		if len(st.str) > 0 && st.str[0] == 'B' {
			a = st.taggedName(a)
		}

		return a
	}
}
func (st *state) substitution(forPrefix bool) AST {
	st.checkChar('S')
	if len(st.str) == 0 {
		st.fail("missing substitution index")
	}
	c := st.str[0]
	st.advance(1)
	dec := 1
	if c == '_' || isDigit(c) || isUpper(c) {
		id := 0
		if c != '_' {
			for c != '_' {
				// Don't overflow a 32-bit int.
				if id >= 0x80000000/36-36 {
					st.fail("substitution index overflow")
				}
				if isDigit(c) {
					id = id*36 + int(c-'0')
				} else if isUpper(c) {
					id = id*36 + int(c-'A') + 10
				} else {
					st.fail("invalid character in substitution index")
				}

				if len(st.str) == 0 {
					st.fail("missing end to substitution index")
				}
				c = st.str[0]
				st.advance(1)
				dec++
			}
			id++
		}

		if id >= len(st.subs) {
			st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), dec)
		}

		ret := st.subs[id]

		// We need to update any references to template
		// parameters to refer to the currently active
		// template.
		copy := func(a AST) AST {
			tp, ok := a.(*TemplateParam)
			if !ok {
				return nil
			}
			if len(st.templates) == 0 {
				st.failEarlier("substituted template parameter not in scope of template", dec)
			}
			template := st.templates[len(st.templates)-1]
			if template == nil {
				// This template parameter is within
				// the scope of a cast operator.
				return &TemplateParam{Index: tp.Index, Template: nil}
			}

			if tp.Index >= len(template.Args) {
				st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", tp.Index, len(template.Args)), dec)
			}

			return &TemplateParam{Index: tp.Index, Template: template}
		}
		var seen []AST
		skip := func(a AST) bool {
			if _, ok := a.(*Typed); ok {
				return true
			}
			for _, v := range seen {
				if v == a {
					return true
				}
			}
			seen = append(seen, a)
			return false
		}
		if c := ret.Copy(copy, skip); c != nil {
			return c
		}

		return ret
	} else {
		m := subAST
		if st.verbose {
			m = verboseAST
		}
		// For compatibility with the standard demangler, use
		// a longer name for a constructor or destructor.
		if forPrefix && len(st.str) > 0 && (st.str[0] == 'C' || st.str[0] == 'D') {
			m = verboseAST
		}
		a, ok := m[c]
		if !ok {
			st.failEarlier("unrecognized substitution code", 1)
		}

		if len(st.str) > 0 && st.str[0] == 'B' {
			a = st.taggedName(a)
		}

		return a
	}
}
// <substitution> ::= S <seq-id> _
//                ::= S_
//                ::= St
//                ::= Sa
//                ::= Sb
//                ::= Ss
//                ::= Si
//                ::= So
//                ::= Sd