demangle.go
func simplifyOne(a AST) AST {
	switch a := a.(type) {
	case *TemplateParam:
		if a.Template != nil && a.Index < len(a.Template.Args) {
			return a.Template.Args[a.Index]
		}
	case *MethodWithQualifiers:
		if m, ok := a.Method.(*MethodWithQualifiers); ok {
			ref := a.RefQualifier
			if ref == "" {
				ref = m.RefQualifier
			} else if m.RefQualifier != "" {
				if ref == "&" || m.RefQualifier == "&" {
					ref = "&"
				}
			}
			return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: ref}
		}
		if t, ok := a.Method.(*TypeWithQualifiers); ok {
			return &MethodWithQualifiers{Method: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers), RefQualifier: a.RefQualifier}
		}
	case *TypeWithQualifiers:
		if ft, ok := a.Base.(*FunctionType); ok {
			return &MethodWithQualifiers{Method: ft, Qualifiers: a.Qualifiers, RefQualifier: ""}
		}
		if t, ok := a.Base.(*TypeWithQualifiers); ok {
			return &TypeWithQualifiers{Base: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers)}
		}
		if m, ok := a.Base.(*MethodWithQualifiers); ok {
			return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: m.RefQualifier}
		}
	case *ReferenceType:
		if rt, ok := a.Base.(*ReferenceType); ok {
			return rt
		}
		if rrt, ok := a.Base.(*RvalueReferenceType); ok {
			return &ReferenceType{Base: rrt.Base}
		}
	case *RvalueReferenceType:
		if rrt, ok := a.Base.(*RvalueReferenceType); ok {
			return rrt
		}
		if rt, ok := a.Base.(*ReferenceType); ok {
			return rt
		}
	case *ArrayType:
		// Qualifiers on the element of an array type
		// go on the whole array type.
		if q, ok := a.Element.(*TypeWithQualifiers); ok {
			return &TypeWithQualifiers{
				Base:       &ArrayType{Dimension: a.Dimension, Element: q.Base},
				Qualifiers: q.Qualifiers,
			}
		}
	case *PackExpansion:
		// Expand the pack and replace it with a list of
		// expressions.
		if a.Pack != nil {
			exprs := make([]AST, len(a.Pack.Args))
			for i, arg := range a.Pack.Args {
				copy := func(sub AST) AST {
					// Replace the ArgumentPack
					// with a specific argument.
					if sub == a.Pack {
						return arg
					}
					// Copy everything else.
					return nil
				}

				var seen []AST
				skip := func(sub AST) bool {
					// Don't traverse into another
					// pack expansion.
					if _, ok := sub.(*PackExpansion); ok {
						return true
					}
					for _, v := range seen {
						if v == sub {
							return true
						}
					}
					seen = append(seen, sub)
					return false
				}

				b := a.Base.Copy(copy, skip)
				if b == nil {
					b = a.Base
				}
				exprs[i] = simplify(b)
			}
			return &ExprList{Exprs: exprs}
		}
	}
	return nil
}
func simplifyOne(a AST) AST {
	switch a := a.(type) {
	case *TemplateParam:
		if a.Template != nil && a.Index < len(a.Template.Args) {
			return a.Template.Args[a.Index]
		}
	case *MethodWithQualifiers:
		if m, ok := a.Method.(*MethodWithQualifiers); ok {
			ref := a.RefQualifier
			if ref == "" {
				ref = m.RefQualifier
			} else if m.RefQualifier != "" {
				if ref == "&" || m.RefQualifier == "&" {
					ref = "&"
				}
			}
			return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: ref}
		}
		if t, ok := a.Method.(*TypeWithQualifiers); ok {
			return &MethodWithQualifiers{Method: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers), RefQualifier: a.RefQualifier}
		}
	case *TypeWithQualifiers:
		if ft, ok := a.Base.(*FunctionType); ok {
			return &MethodWithQualifiers{Method: ft, Qualifiers: a.Qualifiers, RefQualifier: ""}
		}
		if t, ok := a.Base.(*TypeWithQualifiers); ok {
			return &TypeWithQualifiers{Base: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers)}
		}
		if m, ok := a.Base.(*MethodWithQualifiers); ok {
			return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: m.RefQualifier}
		}
	case *ReferenceType:
		if rt, ok := a.Base.(*ReferenceType); ok {
			return rt
		}
		if rrt, ok := a.Base.(*RvalueReferenceType); ok {
			return &ReferenceType{Base: rrt.Base}
		}
	case *RvalueReferenceType:
		if rrt, ok := a.Base.(*RvalueReferenceType); ok {
			return rrt
		}
		if rt, ok := a.Base.(*ReferenceType); ok {
			return rt
		}
	case *ArrayType:
		// Qualifiers on the element of an array type
		// go on the whole array type.
		if q, ok := a.Element.(*TypeWithQualifiers); ok {
			return &TypeWithQualifiers{
				Base:       &ArrayType{Dimension: a.Dimension, Element: q.Base},
				Qualifiers: q.Qualifiers,
			}
		}
	case *PackExpansion:
		// Expand the pack and replace it with a list of
		// expressions.
		if a.Pack != nil {
			exprs := make([]AST, len(a.Pack.Args))
			for i, arg := range a.Pack.Args {
				copy := func(sub AST) AST {
					// Replace the ArgumentPack
					// with a specific argument.
					if sub == a.Pack {
						return arg
					}
					// Copy everything else.
					return nil
				}

				var seen []AST
				skip := func(sub AST) bool {
					// Don't traverse into another
					// pack expansion.
					if _, ok := sub.(*PackExpansion); ok {
						return true
					}
					for _, v := range seen {
						if v == sub {
							return true
						}
					}
					seen = append(seen, sub)
					return false
				}

				b := a.Base.Copy(copy, skip)
				if b == nil {
					b = a.Base
				}
				exprs[i] = simplify(b)
			}
			return &ExprList{Exprs: exprs}
		}
	}
	return nil
}
func simplifyOne ( a AST ) AST { switch a := a . ( type ) { case * TemplateParam : if a . Template != nil && a . Index < len ( a . Template . Args ) { return a . Template . Args [ a . Index ] } case * MethodWithQualifiers : if m , ok := a . Method . ( * MethodWithQualifiers ) ; ok { ref := a . RefQualifier if ref == " " { ref = m . RefQualifier } else if m . RefQualifier != " " { if ref == " " || m . RefQualifier == " " { ref = " " } } return & MethodWithQualifiers { Method : m . Method , Qualifiers : mergeQualifiers ( a . Qualifiers , m . Qualifiers ) , RefQualifier : ref } } if t , ok := a . Method . ( * TypeWithQualifiers ) ; ok { return & MethodWithQualifiers { Method : t . Base , Qualifiers : mergeQualifiers ( a . Qualifiers , t . Qualifiers ) , RefQualifier : a . RefQualifier } } case * TypeWithQualifiers : if ft , ok := a . Base . ( * FunctionType ) ; ok { return & MethodWithQualifiers { Method : ft , Qualifiers : a . Qualifiers , RefQualifier : " " } } if t , ok := a . Base . ( * TypeWithQualifiers ) ; ok { return & TypeWithQualifiers { Base : t . Base , Qualifiers : mergeQualifiers ( a . Qualifiers , t . Qualifiers ) } } if m , ok := a . Base . ( * MethodWithQualifiers ) ; ok { return & MethodWithQualifiers { Method : m . Method , Qualifiers : mergeQualifiers ( a . Qualifiers , m . Qualifiers ) , RefQualifier : m . RefQualifier } } case * ReferenceType : if rt , ok := a . Base . ( * ReferenceType ) ; ok { return rt } if rrt , ok := a . Base . ( * RvalueReferenceType ) ; ok { return & ReferenceType { Base : rrt . Base } } case * RvalueReferenceType : if rrt , ok := a . Base . ( * RvalueReferenceType ) ; ok { return rrt } if rt , ok := a . Base . ( * ReferenceType ) ; ok { return rt } case * ArrayType : // Qualifiers on the element of an array type // go on the whole array type. if q , ok := a . Element . ( * TypeWithQualifiers ) ; ok { return & TypeWithQualifiers { Base : & ArrayType { Dimension : a . Dimension , Element : q . Base } , Qualifiers : q . Qualifiers , } } case * PackExpansion : // Expand the pack and replace it with a list of // expressions. if a . Pack != nil { exprs := make ( [ ] AST , len ( a . Pack . Args ) ) for i , arg := range a . Pack . Args { copy := func ( sub AST ) AST { // Replace the ArgumentPack // with a specific argument. if sub == a . Pack { return arg } // Copy everything else. return nil } var seen [ ] AST skip := func ( sub AST ) bool { // Don't traverse into another // pack expansion. if _ , ok := sub . ( * PackExpansion ) ; ok { return true } for _ , v := range seen { if v == sub { return true } } seen = append ( seen , sub ) return false } b := a . Base . Copy ( copy , skip ) if b == nil { b = a . Base } exprs [ i ] = simplify ( b ) } return & ExprList { Exprs : exprs } } } return nil }
// simplifyOne simplifies a single AST.  It returns nil if there is
// nothing to do.
simplifyOne simplifies a single AST . It returns nil if there is nothing to do .