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
	}
}
func ( st * state ) substitution ( forPrefix bool ) AST { st . checkChar ( 'S' ) if len ( st . str ) == 0 { st . fail ( " " ) } 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 ( " " ) } if isDigit ( c ) { id = id * 36 + int ( c - '0' ) } else if isUpper ( c ) { id = id * 36 + int ( c - 'A' ) + 10 } else { st . fail ( " " ) } if len ( st . str ) == 0 { st . fail ( " " ) } c = st . str [ 0 ] st . advance ( 1 ) dec ++ } id ++ } if id >= len ( st . subs ) { st . failEarlier ( fmt . Sprintf ( " " , 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 ( " " , 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 ( " " , 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 ( " " , 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
<substitution > :: = S <seq - id > _ :: = S_ :: = St :: = Sa :: = Sb :: = Ss :: = Si :: = So :: = Sd