var ErrNotMangledName … type Option … const NoParams … const NoTemplateParams … const NoEnclosingParams … const NoClones … const NoRust … const Verbose … const LLVMStyle … const maxLengthShift … const maxLengthMask … // MaxLength returns an Option that limits the maximum length of a // demangled string. The maximum length is expressed as a power of 2, // so a value of 1 limits the returned string to 2 characters, and // a value of 16 limits the returned string to 65,536 characters. // The value must be between 1 and 30. func MaxLength(pow int) Option { … } // isMaxLength reports whether an Option holds a maximum length. func isMaxLength(opt Option) bool { … } // maxLength returns the maximum length stored in an Option. func maxLength(opt Option) int { … } // Filter demangles a C++ or Rust symbol name, // returning the human-readable C++ or Rust name. // If any error occurs during demangling, the input string is returned. func Filter(name string, options ...Option) string { … } // ToString demangles a C++ or Rust symbol name, // returning a human-readable C++ or Rust name or an error. // If the name does not appear to be a C++ or Rust symbol name at all, // the error will be ErrNotMangledName. func ToString(name string, options ...Option) (string, error) { … } // ToAST demangles a C++ symbol name into an abstract syntax tree // representing the symbol. // If the NoParams option is passed, and the name has a function type, // the parameter types are not demangled. // If the name does not appear to be a C++ symbol name at all, the // error will be ErrNotMangledName. // This function does not currently support Rust symbol names. func ToAST(name string, options ...Option) (AST, error) { … } // globalCDtorName demangles a global constructor/destructor symbol name. // The parameter is the string following the "_GLOBAL_" prefix. func globalCDtorName(name string, options ...Option) (AST, error) { … } // The doDemangle function is the entry point into the demangler proper. func doDemangle(name string, options ...Option) (ret AST, err error) { … } type state … // copy returns a copy of the current state. func (st *state) copy() *state { … } // fail panics with demangleErr, to be caught in doDemangle. func (st *state) fail(err string) { … } // failEarlier is like fail, but decrements the offset to indicate // that the point of failure occurred earlier in the string. func (st *state) failEarlier(err string, dec int) { … } // advance advances the current string offset. func (st *state) advance(add int) { … } // checkChar requires that the next character in the string be c, and // advances past it. func (st *state) checkChar(c byte) { … } type demangleErr … // Error implements the builtin error interface for demangleErr. func (de demangleErr) Error() string { … } // adjustErr adjusts the position of err, if it is a demangleErr, // and returns err. func adjustErr(err error, adj int) error { … } type forLocalNameType … const forLocalName … const notForLocalName … // encoding parses: // // encoding ::= <(function) name> <bare-function-type> // <(data) name> // <special-name> func (st *state) encoding(params bool, local forLocalNameType) AST { … } // hasReturnType returns whether the mangled form of a will have a // return type. func hasReturnType(a AST) bool { … } // isCDtorConversion returns when an AST is a constructor, a // destructor, or a conversion operator. func isCDtorConversion(a AST) bool { … } // taggedName parses: // // <tagged-name> ::= <name> B <source-name> func (st *state) taggedName(a AST) AST { … } // name parses: // // <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> // // Besides the name, this returns whether it saw the code indicating // a C++23 explicit object parameter. func (st *state) name() (AST, bool) { … } // nestedName parses: // // <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E // // Besides the name, this returns whether it saw the code indicating // a C++23 explicit object parameter. func (st *state) nestedName() (AST, bool) { … } // prefix parses: // // <prefix> ::= <prefix> <unqualified-name> // ::= <template-prefix> <template-args> // ::= <template-param> // ::= <decltype> // ::= // ::= <substitution> // // <template-prefix> ::= <prefix> <(template) unqualified-name> // ::= <template-param> // ::= <substitution> // // <decltype> ::= Dt <expression> E // ::= DT <expression> E func (st *state) prefix() AST { … } // unqualifiedName parses: // // <unqualified-name> ::= <operator-name> // ::= <ctor-dtor-name> // ::= <source-name> // ::= <local-source-name> // // <local-source-name> ::= L <source-name> <discriminator> func (st *state) unqualifiedName(module AST) (r AST, isCast bool) { … } // sourceName parses: // // <source-name> ::= <(positive length) number> <identifier> // identifier ::= <(unqualified source code identifier)> func (st *state) sourceName() AST { … } // moduleName parses: // // <module-name> ::= <module-subname> // ::= <module-name> <module-subname> // ::= <substitution> # passed in by caller // <module-subname> ::= W <source-name> // ::= W P <source-name> // // The module name is optional. If it is not present, this returns the parent. func (st *state) moduleName(parent AST) AST { … } // number parses: // // number ::= [n] <(non-negative decimal integer)> func (st *state) number() int { … } // seqID parses: // // <seq-id> ::= <0-9A-Z>+ // // We expect this to be followed by an underscore. func (st *state) seqID(eofOK bool) int { … } type operator … var operators … // operatorName parses: // // operator_name ::= many different two character encodings. // ::= cv <type> // ::= v <digit> <source-name> // // We need to know whether we are in an expression because it affects // how we handle template parameters in the type of a cast operator. func (st *state) operatorName(inExpression bool) (AST, int) { … } // localName parses: // // <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>] // ::= Z <(function) encoding> E s [<discriminator>] // ::= Z <(function) encoding> E d [<parameter> number>] _ <entity name> // // Besides the name, this returns whether it saw the code indicating // a C++23 explicit object parameter. func (st *state) localName() (AST, bool) { … } // Parse a Java resource special-name. func (st *state) javaResource() AST { … } // specialName parses: // // <special-name> ::= TV <type> // ::= TT <type> // ::= TI <type> // ::= TS <type> // ::= TA <template-arg> // ::= GV <(object) name> // ::= T <call-offset> <(base) encoding> // ::= Tc <call-offset> <call-offset> <(base) encoding> // g++ extensions: // ::= TC <type> <(offset) number> _ <(base) type> // ::= TF <type> // ::= TJ <type> // ::= GR <name> // ::= GA <encoding> // ::= Gr <resource name> // ::= GTt <encoding> // ::= GTn <encoding> // ::= GI <module name> func (st *state) specialName() AST { … } // callOffset parses: // // <call-offset> ::= h <nv-offset> _ // ::= v <v-offset> _ // // <nv-offset> ::= <(offset) number> // // <v-offset> ::= <(offset) number> _ <(virtual offset) number> // // The c parameter, if not 0, is a character we just read which is the // start of the <call-offset>. // // We don't display the offset information anywhere. func (st *state) callOffset(c byte) { … } var builtinTypes … // demangleType parses: // // <type> ::= <builtin-type> // ::= <function-type> // ::= <class-enum-type> // ::= <array-type> // ::= <pointer-to-member-type> // ::= <template-param> // ::= <template-template-param> <template-args> // ::= <substitution> // ::= <CV-qualifiers> <type> // ::= P <type> // ::= R <type> // ::= O <type> (C++0x) // ::= C <type> // ::= G <type> // ::= U <source-name> <type> // // <builtin-type> ::= various one letter codes // ::= u <source-name> func (st *state) demangleType(isCast bool) AST { … } // demangleCastTemplateArgs is for a rather hideous parse. When we // see a template-param followed by a template-args, we need to decide // whether we have a template-param or a template-template-param. // Normally it is template-template-param, meaning that we pick up the // template arguments here. But, if we are parsing the type for a // cast operator, then the only way this can be template-template-param // is if there is another set of template-args immediately after this // set. That would look like this: // // <nested-name> // -> <template-prefix> <template-args> // -> <prefix> <template-unqualified-name> <template-args> // -> <unqualified-name> <template-unqualified-name> <template-args> // -> <source-name> <template-unqualified-name> <template-args> // -> <source-name> <operator-name> <template-args> // -> <source-name> cv <type> <template-args> // -> <source-name> cv <template-template-param> <template-args> <template-args> // // Otherwise, we have this derivation: // // <nested-name> // -> <template-prefix> <template-args> // -> <prefix> <template-unqualified-name> <template-args> // -> <unqualified-name> <template-unqualified-name> <template-args> // -> <source-name> <template-unqualified-name> <template-args> // -> <source-name> <operator-name> <template-args> // -> <source-name> cv <type> <template-args> // -> <source-name> cv <template-param> <template-args> // // in which the template-args are actually part of the prefix. For // the special case where this arises, demangleType is called with // isCast as true. This function is then responsible for checking // whether we see <template-param> <template-args> but there is not // another following <template-args>. In that case, we reset the // parse and just return the <template-param>. func (st *state) demangleCastTemplateArgs(tp AST, addSubst bool) AST { … } // mergeQualifiers merges two qualifier lists into one. func mergeQualifiers(q1AST, q2AST AST) AST { … } var qualifiers … // cvQualifiers parses: // // <CV-qualifiers> ::= [r] [V] [K] func (st *state) cvQualifiers() AST { … } // refQualifier parses: // // <ref-qualifier> ::= R // ::= O func (st *state) refQualifier() string { … } // parmlist parses: // // <type>+ func (st *state) parmlist(explicitObjectParameter bool) []AST { … } // functionType parses: // // <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E func (st *state) functionType() AST { … } // bareFunctionType parses: // // <bare-function-type> ::= [J]<type>+ func (st *state) bareFunctionType(hasReturnType, explicitObjectParameter bool) AST { … } // arrayType parses: // // <array-type> ::= A <(positive dimension) number> _ <(element) type> // ::= A [<(dimension) expression>] _ <(element) type> func (st *state) arrayType(isCast bool) AST { … } // vectorType parses: // // <vector-type> ::= Dv <number> _ <type> // ::= Dv _ <expression> _ <type> func (st *state) vectorType(isCast bool) AST { … } // pointerToMemberType parses: // // <pointer-to-member-type> ::= M <(class) type> <(member) type> func (st *state) pointerToMemberType(isCast bool) AST { … } // compactNumber parses: // // <non-negative number> _ func (st *state) compactNumber() int { … } // templateParam parses: // // <template-param> ::= T_ // ::= T <(parameter-2 non-negative) number> _ // ::= TL <level-1> __ // ::= TL <level-1> _ <parameter-2 non-negative number> _ // // When a template parameter is a substitution candidate, any // reference to that substitution refers to the template parameter // with the same index in the currently active template, not to // whatever the template parameter would be expanded to here. We sort // this out in substitution and simplify. func (st *state) templateParam() AST { … } // setTemplate sets the Template field of any TemplateParam's in a. // This handles the forward referencing template parameters found in // cast operators. func (st *state) setTemplate(a AST, tmpl *Template) { … } // clearTemplateArgs gives an error for any unset Template field in // args. This handles erroneous cases where a cast operator with a // forward referenced template is in the scope of another cast // operator. func (st *state) clearTemplateArgs(args []AST) { … } // templateArgs parses: // // <template-args> ::= I <template-arg>+ E func (st *state) templateArgs() []AST { … } // templateArg parses: // // <template-arg> ::= <type> // ::= X <expression> E // ::= <expr-primary> // ::= J <template-arg>* E // ::= LZ <encoding> E // ::= <template-param-decl> <template-arg> func (st *state) templateArg(prev []AST) AST { … } // exprList parses a sequence of expressions up to a terminating character. func (st *state) exprList(stop byte) AST { … } // expression parses: // // <expression> ::= <(unary) operator-name> <expression> // ::= <(binary) operator-name> <expression> <expression> // ::= <(trinary) operator-name> <expression> <expression> <expression> // ::= pp_ <expression> // ::= mm_ <expression> // ::= cl <expression>+ E // ::= cl <expression>+ E // ::= cv <type> <expression> // ::= cv <type> _ <expression>* E // ::= tl <type> <braced-expression>* E // ::= il <braced-expression>* E // ::= [gs] nw <expression>* _ <type> E // ::= [gs] nw <expression>* _ <type> <initializer> // ::= [gs] na <expression>* _ <type> E // ::= [gs] na <expression>* _ <type> <initializer> // ::= [gs] dl <expression> // ::= [gs] da <expression> // ::= dc <type> <expression> // ::= sc <type> <expression> // ::= cc <type> <expression> // ::= mc <parameter type> <expr> [<offset number>] E // ::= rc <type> <expression> // ::= ti <type> // ::= te <expression> // ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E // ::= st <type> // ::= sz <expression> // ::= at <type> // ::= az <expression> // ::= nx <expression> // ::= <template-param> // ::= <function-param> // ::= dt <expression> <unresolved-name> // ::= pt <expression> <unresolved-name> // ::= ds <expression> <expression> // ::= sZ <template-param> // ::= sZ <function-param> // ::= sP <template-arg>* E // ::= sp <expression> // ::= fl <binary operator-name> <expression> // ::= fr <binary operator-name> <expression> // ::= fL <binary operator-name> <expression> <expression> // ::= fR <binary operator-name> <expression> <expression> // ::= tw <expression> // ::= tr // ::= u <source-name> <template-arg>* E // ::= <unresolved-name> // ::= <expr-primary> // // <function-param> ::= fp <CV-qualifiers> _ // ::= fp <CV-qualifiers> <number> // ::= fL <number> p <CV-qualifiers> _ // ::= fL <number> p <CV-qualifiers> <number> // ::= fpT // // <braced-expression> ::= <expression> // ::= di <field source-name> <braced-expression> // ::= dx <index expression> <braced-expression> // ::= dX <range begin expression> <range end expression> <braced-expression> func (st *state) expression() AST { … } // subobject parses: // // <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E // <union-selector> ::= _ [<number>] func (st *state) subobject() AST { … } // unresolvedName parses: // // <unresolved-name> ::= [gs] <base-unresolved-name> // ::= sr <unresolved-type> <base-unresolved-name> // ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> // ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> func (st *state) unresolvedName() AST { … } // baseUnresolvedName parses: // // <base-unresolved-name> ::= <simple-id> // ::= on <operator-name> // ::= on <operator-name> <template-args> // ::= dn <destructor-name> // // <simple-id> ::= <source-name> [ <template-args> ] func (st *state) baseUnresolvedName() AST { … } // requiresExpr parses: // // <expression> ::= rQ <bare-function-type> _ <requirement>+ E // ::= rq <requirement>+ E // <requirement> ::= X <expression> [N] [R <type-constraint>] // ::= T <type> // ::= Q <constraint-expression> func (st *state) requiresExpr() AST { … } // exprPrimary parses: // // <expr-primary> ::= L <type> <(value) number> E // ::= L <type> <(value) float> E // ::= L <mangled-name> E func (st *state) exprPrimary() AST { … } // discriminator parses: // // <discriminator> ::= _ <(non-negative) number> (when number < 10) // __ <(non-negative) number> _ (when number >= 10) func (st *state) discriminator(a AST) AST { … } // closureTypeName parses: // // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ // <lambda-sig> ::= <parameter type>+ func (st *state) closureTypeName() AST { … } // templateParamDecl parses: // // <template-param-decl> ::= Ty # type parameter // ::= Tn <type> # non-type parameter // ::= Tt <template-param-decl>* E # template parameter // ::= Tp <template-param-decl> # parameter pack // // Returns the new AST to include in the AST we are building and the // new AST to add to the list of template parameters. // // Returns nil, nil if not looking at a template-param-decl. func (st *state) templateParamDecl() (AST, AST) { … } // unnamedTypeName parses: // // <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ func (st *state) unnamedTypeName() AST { … } // constraintExpr parses a constraint expression. This is just a // regular expression, but template parameters are handled specially. func (st *state) constraintExpr() AST { … } // Recognize a clone suffix. These are not part of the mangling API, // but are added by GCC when cloning functions. func (st *state) cloneSuffix(a AST) AST { … } type substitutions … // add adds a new substitution candidate. func (subs *substitutions) add(a AST) { … } var subAST … var verboseAST … // substitution parses: // // <substitution> ::= S <seq-id> _ // ::= S_ // ::= St // ::= Sa // ::= Sb // ::= Ss // ::= Si // ::= So // ::= Sd func (st *state) substitution(forPrefix bool) AST { … } // isDigit returns whetner c is a digit for demangling purposes. func isDigit(c byte) bool { … } // isUpper returns whether c is an upper case letter for demangling purposes. func isUpper(c byte) bool { … } // isLower returns whether c is a lower case letter for demangling purposes. func isLower(c byte) bool { … } // simplify replaces template parameters with their expansions, and // merges qualifiers. func simplify(a AST) AST { … } // simplifyOne simplifies a single AST. It returns nil if there is // nothing to do. func simplifyOne(a AST) AST { … } // findArgumentPack walks the AST looking for the argument pack for a // pack expansion. We find it via a template parameter. func (st *state) findArgumentPack(a AST) *ArgumentPack { … }