demangle.go
func (st *state) name() AST {
	if len(st.str) < 1 {
		st.fail("expected name")
	}
	switch st.str[0] {
	case 'N':
		return st.nestedName()
	case 'Z':
		return st.localName()
	case 'U':
		a, isCast := st.unqualifiedName()
		if isCast {
			st.setTemplate(a, nil)
		}
		return a
	case 'S':
		if len(st.str) < 2 {
			st.advance(1)
			st.fail("expected substitution index")
		}
		var a AST
		isCast := false
		subst := false
		if st.str[1] == 't' {
			st.advance(2)
			a, isCast = st.unqualifiedName()
			a = &Qualified{Scope: &Name{Name: "std"}, Name: a, LocalName: false}
		} else {
			a = st.substitution(false)
			subst = true
		}
		if len(st.str) > 0 && st.str[0] == 'I' {
			// This can only happen if we saw
			// <unscoped-template-name> and are about to see
			// <template-args>.  <unscoped-template-name> is a
			// substitution candidate if it did not come from a
			// substitution.
			if !subst {
				st.subs.add(a)
			}
			args := st.templateArgs()
			tmpl := &Template{Name: a, Args: args}
			if isCast {
				st.setTemplate(a, tmpl)
				st.clearTemplateArgs(args)
				isCast = false
			}
			a = tmpl
		}
		if isCast {
			st.setTemplate(a, nil)
		}
		return a

	default:
		a, isCast := st.unqualifiedName()
		if len(st.str) > 0 && st.str[0] == 'I' {
			st.subs.add(a)
			args := st.templateArgs()
			tmpl := &Template{Name: a, Args: args}
			if isCast {
				st.setTemplate(a, tmpl)
				st.clearTemplateArgs(args)
				isCast = false
			}
			a = tmpl
		}
		if isCast {
			st.setTemplate(a, nil)
		}
		return a
	}
}
func (st *state) name() AST {
	if len(st.str) < 1 {
		st.fail("expected name")
	}
	switch st.str[0] {
	case 'N':
		return st.nestedName()
	case 'Z':
		return st.localName()
	case 'U':
		a, isCast := st.unqualifiedName()
		if isCast {
			st.setTemplate(a, nil)
		}
		return a
	case 'S':
		if len(st.str) < 2 {
			st.advance(1)
			st.fail("expected substitution index")
		}
		var a AST
		isCast := false
		subst := false
		if st.str[1] == 't' {
			st.advance(2)
			a, isCast = st.unqualifiedName()
			a = &Qualified{Scope: &Name{Name: "std"}, Name: a, LocalName: false}
		} else {
			a = st.substitution(false)
			subst = true
		}
		if len(st.str) > 0 && st.str[0] == 'I' {
			// This can only happen if we saw
			// <unscoped-template-name> and are about to see
			// <template-args>.  <unscoped-template-name> is a
			// substitution candidate if it did not come from a
			// substitution.
			if !subst {
				st.subs.add(a)
			}
			args := st.templateArgs()
			tmpl := &Template{Name: a, Args: args}
			if isCast {
				st.setTemplate(a, tmpl)
				st.clearTemplateArgs(args)
				isCast = false
			}
			a = tmpl
		}
		if isCast {
			st.setTemplate(a, nil)
		}
		return a

	default:
		a, isCast := st.unqualifiedName()
		if len(st.str) > 0 && st.str[0] == 'I' {
			st.subs.add(a)
			args := st.templateArgs()
			tmpl := &Template{Name: a, Args: args}
			if isCast {
				st.setTemplate(a, tmpl)
				st.clearTemplateArgs(args)
				isCast = false
			}
			a = tmpl
		}
		if isCast {
			st.setTemplate(a, nil)
		}
		return a
	}
}
// <name> ::= <nested-name>
//        ::= <unscoped-name>
//        ::= <unscoped-template-name> <template-args>
//        ::= <local-name>
//
// <unscoped-name> ::= <unqualified-name>
//                 ::= St <unqualified-name>
//
// <unscoped-template-name> ::= <unscoped-name>
//                          ::= <substitution>