Showing preview only (5,660K chars total). Download the full file or copy to clipboard to get everything.
Repository: ianlancetaylor/demangle
Branch: master
Commit: 1ff4bf46051f
Files: 19
Total size: 5.4 MB
Directory structure:
gitextract_d03jdduc/
├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── ast.go
├── ast_test.go
├── c++filt.go
├── cases_test.go
├── demangle.go
├── demangle_test.go
├── expected_test.go
├── fuzz_test.go
├── go.mod
├── rust.go
├── rust_expected_test.go
└── testdata/
├── DemangleTestCases.inc
├── demangle-expected
├── rust-demangle-expected
└── rust.test
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.o
*.a
*.so
._*
.nfs.*
a.out
*~
*.orig
*.rej
*.exe
.*.swp
core
demangle.test
================================================
FILE: LICENSE
================================================
Copyright (c) 2015 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README.md
================================================
# github.com/ianlancetaylor/demangle
A Go package that can be used to demangle C++ and Rust symbol names.
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
Security updates are applied only to the latest release.
## Reporting a Vulnerability
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
Please disclose it at [security advisory](https://github.com/ianlancetaylor/demangle/security/advisories/new).
This project is maintained by volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.
================================================
FILE: ast.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package demangle
import (
"fmt"
"strconv"
"strings"
)
// AST is an abstract syntax tree representing a C++ declaration.
// This is sufficient for the demangler but is by no means a general C++ AST.
// This abstract syntax tree is only used for C++ symbols, not Rust symbols.
type AST interface {
// Internal method to convert to demangled string.
print(*printState)
// Traverse each element of an AST. If the function returns
// false, traversal of children of that element is skipped.
Traverse(func(AST) bool)
// Copy an AST with possible transformations.
// If the skip function returns true, no copy is required.
// If the copy function returns nil, no copy is required.
// The Copy method will do the right thing if copy returns nil
// for some components of an AST but not others, so a good
// copy function will only return non-nil for AST values that
// need to change.
// Copy itself returns either a copy or nil.
Copy(copy func(AST) AST, skip func(AST) bool) AST
// Implement the fmt.GoStringer interface.
GoString() string
goString(indent int, field string) string
}
// ASTToString returns the demangled name of the AST.
func ASTToString(a AST, options ...Option) string {
tparams := true
enclosingParams := true
llvmStyle := false
max := 0
for _, o := range options {
switch {
case o == NoTemplateParams:
tparams = false
case o == NoEnclosingParams:
enclosingParams = false
case o == LLVMStyle:
llvmStyle = true
case isMaxLength(o):
max = maxLength(o)
}
}
ps := printState{
tparams: tparams,
enclosingParams: enclosingParams,
llvmStyle: llvmStyle,
max: max,
scopes: 1,
}
a.print(&ps)
s := ps.buf.String()
if max > 0 && len(s) > max {
s = s[:max]
}
return s
}
// The printState type holds information needed to print an AST.
type printState struct {
tparams bool // whether to print template parameters
enclosingParams bool // whether to print enclosing parameters
llvmStyle bool
max int // maximum output length
// The scopes field is used to avoid unnecessary parentheses
// around expressions that use > (or >>). It is incremented if
// we output a parenthesis or something else that means that >
// or >> won't be treated as ending a template. It starts out
// as 1, and is set to 0 when we start writing template
// arguments. We add parentheses around expressions using > if
// scopes is 0. The effect is that an expression with > gets
// parentheses if used as a template argument that is not
// inside some other set of parentheses.
scopes int
// lambdaTemplateArgs is true if we are printing the template
// arguments to a lambda with explicit template parameters.
// In that case template parameters are printed without names.
lambdaTemplateArgs bool
buf strings.Builder
last byte // Last byte written to buffer.
// The inner field is a list of items to print for a type
// name. This is used by types to implement the inside-out
// C++ declaration syntax.
inner []AST
// The printing field is a list of items we are currently
// printing. This avoids endless recursion if a substitution
// reference creates a cycle in the graph.
printing []AST
}
// writeByte adds a byte to the string being printed.
func (ps *printState) writeByte(b byte) {
ps.last = b
ps.buf.WriteByte(b)
}
// writeString adds a string to the string being printed.
func (ps *printState) writeString(s string) {
if len(s) > 0 {
ps.last = s[len(s)-1]
}
ps.buf.WriteString(s)
}
// Print an AST.
func (ps *printState) print(a AST) {
if ps.max > 0 && ps.buf.Len() > ps.max {
return
}
c := 0
for _, v := range ps.printing {
if v == a {
// We permit the type to appear once, and
// return without printing anything if we see
// it twice. This is for a case like
// _Z6outer2IsEPFilES1_, where the
// substitution is printed differently the
// second time because the set of inner types
// is different.
c++
if c > 1 {
return
}
}
}
ps.printing = append(ps.printing, a)
a.print(ps)
ps.printing = ps.printing[:len(ps.printing)-1]
}
// printList prints a list of AST values separated by commas,
// optionally skipping some.
func (ps *printState) printList(args []AST, skip func(AST) bool) {
first := true
for _, a := range args {
if skip != nil && skip(a) {
continue
}
if !first {
ps.writeString(", ")
}
needsParen := false
if ps.llvmStyle {
if p, ok := a.(hasPrec); ok {
if p.prec() >= precComma {
needsParen = true
}
}
}
if needsParen {
ps.startScope('(')
}
ps.print(a)
if needsParen {
ps.endScope(')')
}
first = false
}
}
// startScope starts a scope. This is used to decide whether we need
// to parenthesize an expression using > or >>.
func (ps *printState) startScope(b byte) {
ps.scopes++
ps.writeByte(b)
}
// endScope closes a scope.
func (ps *printState) endScope(b byte) {
ps.scopes--
ps.writeByte(b)
}
// precedence is used for operator precedence. This is used to avoid
// unnecessary parentheses when printing expressions in the LLVM style.
type precedence int
// The precedence values, in order from high to low.
const (
precPrimary precedence = iota
precPostfix
precUnary
precCast
precPtrMem
precMul
precAdd
precShift
precSpaceship
precRel
precEqual
precAnd
precXor
precOr
precLogicalAnd
precLogicalOr
precCond
precAssign
precComma
precDefault
)
// hasPrec matches the AST nodes that have a prec method that returns
// the node's precedence.
type hasPrec interface {
prec() precedence
}
// Name is an unqualified name.
type Name struct {
Name string
}
func (n *Name) print(ps *printState) {
ps.writeString(n.Name)
}
func (n *Name) Traverse(fn func(AST) bool) {
fn(n)
}
func (n *Name) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(n) {
return nil
}
return fn(n)
}
func (n *Name) GoString() string {
return n.goString(0, "Name: ")
}
func (n *Name) goString(indent int, field string) string {
return fmt.Sprintf("%*s%s%s", indent, "", field, n.Name)
}
func (n *Name) prec() precedence {
return precPrimary
}
// Typed is a typed name.
type Typed struct {
Name AST
Type AST
}
func (t *Typed) print(ps *printState) {
// We are printing a typed name, so ignore the current set of
// inner names to print. Pass down our name as the one to use.
holdInner := ps.inner
defer func() { ps.inner = holdInner }()
ps.inner = []AST{t}
ps.print(t.Type)
if len(ps.inner) > 0 {
// The type did not print the name; print it now in
// the default location.
ps.writeByte(' ')
ps.print(t.Name)
}
}
func (t *Typed) printInner(ps *printState) {
ps.print(t.Name)
}
func (t *Typed) Traverse(fn func(AST) bool) {
if fn(t) {
t.Name.Traverse(fn)
t.Type.Traverse(fn)
}
}
func (t *Typed) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(t) {
return nil
}
name := t.Name.Copy(fn, skip)
typ := t.Type.Copy(fn, skip)
if name == nil && typ == nil {
return fn(t)
}
if name == nil {
name = t.Name
}
if typ == nil {
typ = t.Type
}
t = &Typed{Name: name, Type: typ}
if r := fn(t); r != nil {
return r
}
return t
}
func (t *Typed) GoString() string {
return t.goString(0, "")
}
func (t *Typed) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTyped:\n%s\n%s", indent, "", field,
t.Name.goString(indent+2, "Name: "),
t.Type.goString(indent+2, "Type: "))
}
// Qualified is a name in a scope.
type Qualified struct {
Scope AST
Name AST
// The LocalName field is true if this is parsed as a
// <local-name>. We shouldn't really need this, but in some
// cases (for the unary sizeof operator) the standard
// demangler prints a local name slightly differently. We
// keep track of this for compatibility.
LocalName bool // A full local name encoding
}
func (q *Qualified) print(ps *printState) {
ps.print(q.Scope)
ps.writeString("::")
ps.print(q.Name)
}
func (q *Qualified) Traverse(fn func(AST) bool) {
if fn(q) {
q.Scope.Traverse(fn)
q.Name.Traverse(fn)
}
}
func (q *Qualified) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(q) {
return nil
}
scope := q.Scope.Copy(fn, skip)
name := q.Name.Copy(fn, skip)
if scope == nil && name == nil {
return fn(q)
}
if scope == nil {
scope = q.Scope
}
if name == nil {
name = q.Name
}
q = &Qualified{Scope: scope, Name: name, LocalName: q.LocalName}
if r := fn(q); r != nil {
return r
}
return q
}
func (q *Qualified) GoString() string {
return q.goString(0, "")
}
func (q *Qualified) goString(indent int, field string) string {
s := ""
if q.LocalName {
s = " LocalName: true"
}
return fmt.Sprintf("%*s%sQualified:%s\n%s\n%s", indent, "", field,
s, q.Scope.goString(indent+2, "Scope: "),
q.Name.goString(indent+2, "Name: "))
}
func (q *Qualified) prec() precedence {
return precPrimary
}
// Template is a template with arguments.
type Template struct {
Name AST
Args []AST
}
func (t *Template) print(ps *printState) {
// Inner types apply to the template as a whole, they don't
// cross over into the template.
holdInner := ps.inner
defer func() { ps.inner = holdInner }()
ps.inner = nil
ps.print(t.Name)
if !ps.tparams {
// Do not print template parameters.
return
}
// We need an extra space after operator<.
if ps.last == '<' {
ps.writeByte(' ')
}
scopes := ps.scopes
ps.scopes = 0
ps.writeByte('<')
ps.printList(t.Args, ps.isEmpty)
if ps.last == '>' && !ps.llvmStyle {
// Avoid syntactic ambiguity in old versions of C++.
ps.writeByte(' ')
}
ps.writeByte('>')
ps.scopes = scopes
}
func (t *Template) Traverse(fn func(AST) bool) {
if fn(t) {
t.Name.Traverse(fn)
for _, a := range t.Args {
a.Traverse(fn)
}
}
}
func (t *Template) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(t) {
return nil
}
name := t.Name.Copy(fn, skip)
changed := name != nil
args := make([]AST, len(t.Args))
for i, a := range t.Args {
ac := a.Copy(fn, skip)
if ac == nil {
args[i] = a
} else {
args[i] = ac
changed = true
}
}
if !changed {
return fn(t)
}
if name == nil {
name = t.Name
}
t = &Template{Name: name, Args: args}
if r := fn(t); r != nil {
return r
}
return t
}
func (t *Template) GoString() string {
return t.goString(0, "")
}
func (t *Template) goString(indent int, field string) string {
var args string
if len(t.Args) == 0 {
args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
} else {
args = fmt.Sprintf("%*sArgs:", indent+2, "")
for i, a := range t.Args {
args += "\n"
args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
}
}
return fmt.Sprintf("%*s%sTemplate (%p):\n%s\n%s", indent, "", field, t,
t.Name.goString(indent+2, "Name: "), args)
}
// TemplateParam is a template parameter. The Template field is
// filled in while parsing the demangled string. We don't normally
// see these while printing--they are replaced by the simplify
// function.
type TemplateParam struct {
Index int
Template *Template
}
func (tp *TemplateParam) print(ps *printState) {
if tp.Template == nil {
panic("TemplateParam Template field is nil")
}
if tp.Index >= len(tp.Template.Args) {
panic("TemplateParam Index out of bounds")
}
ps.print(tp.Template.Args[tp.Index])
}
func (tp *TemplateParam) Traverse(fn func(AST) bool) {
fn(tp)
// Don't traverse Template--it points elsewhere in the AST.
}
func (tp *TemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(tp) {
return nil
}
return fn(tp)
}
func (tp *TemplateParam) GoString() string {
return tp.goString(0, "")
}
func (tp *TemplateParam) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTemplateParam: Template: %p; Index %d", indent, "", field, tp.Template, tp.Index)
}
// LambdaAuto is a lambda auto parameter.
type LambdaAuto struct {
Index int
}
func (la *LambdaAuto) print(ps *printState) {
// We print the index plus 1 because that is what the standard
// demangler does.
if ps.llvmStyle {
ps.writeString("auto")
} else {
fmt.Fprintf(&ps.buf, "auto:%d", la.Index+1)
}
}
func (la *LambdaAuto) Traverse(fn func(AST) bool) {
fn(la)
}
func (la *LambdaAuto) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(la) {
return nil
}
return fn(la)
}
func (la *LambdaAuto) GoString() string {
return la.goString(0, "")
}
func (la *LambdaAuto) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sLambdaAuto: Index %d", indent, "", field, la.Index)
}
// TemplateParamQualifiedArg is used when the mangled name includes
// both the template parameter declaration and the template argument.
// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
type TemplateParamQualifiedArg struct {
Param AST
Arg AST
}
func (tpqa *TemplateParamQualifiedArg) print(ps *printState) {
// We only demangle the actual template argument.
// That is what the LLVM demangler does.
// The parameter disambiguates the argument,
// but is hopefully not required by a human reader.
ps.print(tpqa.Arg)
}
func (tpqa *TemplateParamQualifiedArg) Traverse(fn func(AST) bool) {
if fn(tpqa) {
tpqa.Param.Traverse(fn)
tpqa.Arg.Traverse(fn)
}
}
func (tpqa *TemplateParamQualifiedArg) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(tpqa) {
return nil
}
param := tpqa.Param.Copy(fn, skip)
arg := tpqa.Arg.Copy(fn, skip)
if param == nil && arg == nil {
return fn(tpqa)
}
if param == nil {
param = tpqa.Param
}
if arg == nil {
arg = tpqa.Arg
}
tpqa = &TemplateParamQualifiedArg{Param: param, Arg: arg}
if r := fn(tpqa); r != nil {
return r
}
return tpqa
}
func (tpqa *TemplateParamQualifiedArg) GoString() string {
return tpqa.goString(0, "")
}
func (tpqa *TemplateParamQualifiedArg) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTemplateParamQualifiedArg:\n%s\n%s", indent, "", field,
tpqa.Param.goString(indent+2, "Param: "),
tpqa.Arg.goString(indent+2, "Arg: "))
}
// Qualifiers is an ordered list of type qualifiers.
type Qualifiers struct {
Qualifiers []AST
}
func (qs *Qualifiers) print(ps *printState) {
first := true
for _, q := range qs.Qualifiers {
if !first {
ps.writeByte(' ')
}
q.print(ps)
first = false
}
}
func (qs *Qualifiers) Traverse(fn func(AST) bool) {
if fn(qs) {
for _, q := range qs.Qualifiers {
q.Traverse(fn)
}
}
}
func (qs *Qualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(qs) {
return nil
}
changed := false
qualifiers := make([]AST, len(qs.Qualifiers))
for i, q := range qs.Qualifiers {
qc := q.Copy(fn, skip)
if qc == nil {
qualifiers[i] = q
} else {
qualifiers[i] = qc
changed = true
}
}
if !changed {
return fn(qs)
}
qs = &Qualifiers{Qualifiers: qualifiers}
if r := fn(qs); r != nil {
return r
}
return qs
}
func (qs *Qualifiers) GoString() string {
return qs.goString(0, "")
}
func (qs *Qualifiers) goString(indent int, field string) string {
quals := fmt.Sprintf("%*s%s", indent, "", field)
for _, q := range qs.Qualifiers {
quals += "\n"
quals += q.goString(indent+2, "")
}
return quals
}
// Qualifier is a single type qualifier.
type Qualifier struct {
Name string // qualifier name: const, volatile, etc.
Exprs []AST // can be non-nil for noexcept and throw
}
func (q *Qualifier) print(ps *printState) {
ps.writeString(q.Name)
if len(q.Exprs) > 0 {
ps.startScope('(')
first := true
for _, e := range q.Exprs {
if el, ok := e.(*ExprList); ok && len(el.Exprs) == 0 {
continue
}
if !first {
ps.writeString(", ")
}
ps.print(e)
first = false
}
ps.endScope(')')
}
}
func (q *Qualifier) Traverse(fn func(AST) bool) {
if fn(q) {
for _, e := range q.Exprs {
e.Traverse(fn)
}
}
}
func (q *Qualifier) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(q) {
return nil
}
exprs := make([]AST, len(q.Exprs))
changed := false
for i, e := range q.Exprs {
ec := e.Copy(fn, skip)
if ec == nil {
exprs[i] = e
} else {
exprs[i] = ec
changed = true
}
}
if !changed {
return fn(q)
}
q = &Qualifier{Name: q.Name, Exprs: exprs}
if r := fn(q); r != nil {
return r
}
return q
}
func (q *Qualifier) GoString() string {
return q.goString(0, "Qualifier: ")
}
func (q *Qualifier) goString(indent int, field string) string {
qs := fmt.Sprintf("%*s%s%s", indent, "", field, q.Name)
if len(q.Exprs) > 0 {
for i, e := range q.Exprs {
qs += "\n"
qs += e.goString(indent+2, fmt.Sprintf("%d: ", i))
}
}
return qs
}
// TypeWithQualifiers is a type with standard qualifiers.
type TypeWithQualifiers struct {
Base AST
Qualifiers AST
}
func (twq *TypeWithQualifiers) print(ps *printState) {
// Give the base type a chance to print the inner types.
ps.inner = append(ps.inner, twq)
ps.print(twq.Base)
if len(ps.inner) > 0 {
// The qualifier wasn't printed by Base.
ps.writeByte(' ')
ps.print(twq.Qualifiers)
// In implausible situations like a throw qualified by a throw,
// we may have printed the qualifier already,
// so check the length of ps.inner again.
if len(ps.inner) > 0 {
ps.inner = ps.inner[:len(ps.inner)-1]
}
}
}
// Print qualifiers as an inner type by just printing the qualifiers.
func (twq *TypeWithQualifiers) printInner(ps *printState) {
ps.writeByte(' ')
ps.print(twq.Qualifiers)
}
func (twq *TypeWithQualifiers) Traverse(fn func(AST) bool) {
if fn(twq) {
twq.Base.Traverse(fn)
}
}
func (twq *TypeWithQualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(twq) {
return nil
}
base := twq.Base.Copy(fn, skip)
quals := twq.Qualifiers.Copy(fn, skip)
if base == nil && quals == nil {
return fn(twq)
}
if base == nil {
base = twq.Base
}
if quals == nil {
quals = twq.Qualifiers
}
twq = &TypeWithQualifiers{Base: base, Qualifiers: quals}
if r := fn(twq); r != nil {
return r
}
return twq
}
func (twq *TypeWithQualifiers) GoString() string {
return twq.goString(0, "")
}
func (twq *TypeWithQualifiers) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTypeWithQualifiers:\n%s\n%s", indent, "", field,
twq.Qualifiers.goString(indent+2, "Qualifiers: "),
twq.Base.goString(indent+2, "Base: "))
}
// MethodWithQualifiers is a method with qualifiers.
type MethodWithQualifiers struct {
Method AST
Qualifiers AST
RefQualifier string // "" or "&" or "&&"
}
func (mwq *MethodWithQualifiers) print(ps *printState) {
// Give the base type a chance to print the inner types.
ps.inner = append(ps.inner, mwq)
ps.print(mwq.Method)
if len(ps.inner) > 0 {
if mwq.Qualifiers != nil {
ps.writeByte(' ')
ps.print(mwq.Qualifiers)
}
if mwq.RefQualifier != "" {
ps.writeByte(' ')
ps.writeString(mwq.RefQualifier)
}
ps.inner = ps.inner[:len(ps.inner)-1]
}
}
func (mwq *MethodWithQualifiers) printInner(ps *printState) {
if mwq.Qualifiers != nil {
ps.writeByte(' ')
ps.print(mwq.Qualifiers)
}
if mwq.RefQualifier != "" {
ps.writeByte(' ')
ps.writeString(mwq.RefQualifier)
}
}
func (mwq *MethodWithQualifiers) Traverse(fn func(AST) bool) {
if fn(mwq) {
mwq.Method.Traverse(fn)
}
}
func (mwq *MethodWithQualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(mwq) {
return nil
}
method := mwq.Method.Copy(fn, skip)
var quals AST
if mwq.Qualifiers != nil {
quals = mwq.Qualifiers.Copy(fn, skip)
}
if method == nil && quals == nil {
return fn(mwq)
}
if method == nil {
method = mwq.Method
}
if quals == nil {
quals = mwq.Qualifiers
}
mwq = &MethodWithQualifiers{Method: method, Qualifiers: quals, RefQualifier: mwq.RefQualifier}
if r := fn(mwq); r != nil {
return r
}
return mwq
}
func (mwq *MethodWithQualifiers) GoString() string {
return mwq.goString(0, "")
}
func (mwq *MethodWithQualifiers) goString(indent int, field string) string {
var q string
if mwq.Qualifiers != nil {
q += "\n" + mwq.Qualifiers.goString(indent+2, "Qualifiers: ")
}
if mwq.RefQualifier != "" {
if q != "" {
q += "\n"
}
q += fmt.Sprintf("%*s%s%s", indent+2, "", "RefQualifier: ", mwq.RefQualifier)
}
return fmt.Sprintf("%*s%sMethodWithQualifiers:%s\n%s", indent, "", field,
q, mwq.Method.goString(indent+2, "Method: "))
}
// BuiltinType is a builtin type, like "int".
type BuiltinType struct {
Name string
}
func (bt *BuiltinType) print(ps *printState) {
name := bt.Name
if ps.llvmStyle && name == "decltype(nullptr)" {
name = "std::nullptr_t"
}
ps.writeString(name)
}
func (bt *BuiltinType) Traverse(fn func(AST) bool) {
fn(bt)
}
func (bt *BuiltinType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(bt) {
return nil
}
return fn(bt)
}
func (bt *BuiltinType) GoString() string {
return bt.goString(0, "")
}
func (bt *BuiltinType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sBuiltinType: %s", indent, "", field, bt.Name)
}
func (bt *BuiltinType) prec() precedence {
return precPrimary
}
// printBase is common print code for types that are printed with a
// simple suffix.
func printBase(ps *printState, qual, base AST) {
ps.inner = append(ps.inner, qual)
ps.print(base)
if len(ps.inner) > 0 {
qual.(innerPrinter).printInner(ps)
ps.inner = ps.inner[:len(ps.inner)-1]
}
}
// PointerType is a pointer type.
type PointerType struct {
Base AST
}
func (pt *PointerType) print(ps *printState) {
printBase(ps, pt, pt.Base)
}
func (pt *PointerType) printInner(ps *printState) {
ps.writeString("*")
}
func (pt *PointerType) Traverse(fn func(AST) bool) {
if fn(pt) {
pt.Base.Traverse(fn)
}
}
func (pt *PointerType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(pt) {
return nil
}
base := pt.Base.Copy(fn, skip)
if base == nil {
return fn(pt)
}
pt = &PointerType{Base: base}
if r := fn(pt); r != nil {
return r
}
return pt
}
func (pt *PointerType) GoString() string {
return pt.goString(0, "")
}
func (pt *PointerType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sPointerType:\n%s", indent, "", field,
pt.Base.goString(indent+2, ""))
}
// ReferenceType is a reference type.
type ReferenceType struct {
Base AST
}
func (rt *ReferenceType) print(ps *printState) {
printBase(ps, rt, rt.Base)
}
func (rt *ReferenceType) printInner(ps *printState) {
ps.writeString("&")
}
func (rt *ReferenceType) Traverse(fn func(AST) bool) {
if fn(rt) {
rt.Base.Traverse(fn)
}
}
func (rt *ReferenceType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(rt) {
return nil
}
base := rt.Base.Copy(fn, skip)
if base == nil {
return fn(rt)
}
rt = &ReferenceType{Base: base}
if r := fn(rt); r != nil {
return r
}
return rt
}
func (rt *ReferenceType) GoString() string {
return rt.goString(0, "")
}
func (rt *ReferenceType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sReferenceType:\n%s", indent, "", field,
rt.Base.goString(indent+2, ""))
}
// RvalueReferenceType is an rvalue reference type.
type RvalueReferenceType struct {
Base AST
}
func (rt *RvalueReferenceType) print(ps *printState) {
printBase(ps, rt, rt.Base)
}
func (rt *RvalueReferenceType) printInner(ps *printState) {
ps.writeString("&&")
}
func (rt *RvalueReferenceType) Traverse(fn func(AST) bool) {
if fn(rt) {
rt.Base.Traverse(fn)
}
}
func (rt *RvalueReferenceType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(rt) {
return nil
}
base := rt.Base.Copy(fn, skip)
if base == nil {
return fn(rt)
}
rt = &RvalueReferenceType{Base: base}
if r := fn(rt); r != nil {
return r
}
return rt
}
func (rt *RvalueReferenceType) GoString() string {
return rt.goString(0, "")
}
func (rt *RvalueReferenceType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sRvalueReferenceType:\n%s", indent, "", field,
rt.Base.goString(indent+2, ""))
}
// ComplexType is a complex type.
type ComplexType struct {
Base AST
}
func (ct *ComplexType) print(ps *printState) {
printBase(ps, ct, ct.Base)
}
func (ct *ComplexType) printInner(ps *printState) {
ps.writeString(" _Complex")
}
func (ct *ComplexType) Traverse(fn func(AST) bool) {
if fn(ct) {
ct.Base.Traverse(fn)
}
}
func (ct *ComplexType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(ct) {
return nil
}
base := ct.Base.Copy(fn, skip)
if base == nil {
return fn(ct)
}
ct = &ComplexType{Base: base}
if r := fn(ct); r != nil {
return r
}
return ct
}
func (ct *ComplexType) GoString() string {
return ct.goString(0, "")
}
func (ct *ComplexType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sComplexType:\n%s", indent, "", field,
ct.Base.goString(indent+2, ""))
}
// ImaginaryType is an imaginary type.
type ImaginaryType struct {
Base AST
}
func (it *ImaginaryType) print(ps *printState) {
printBase(ps, it, it.Base)
}
func (it *ImaginaryType) printInner(ps *printState) {
ps.writeString(" _Imaginary")
}
func (it *ImaginaryType) Traverse(fn func(AST) bool) {
if fn(it) {
it.Base.Traverse(fn)
}
}
func (it *ImaginaryType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(it) {
return nil
}
base := it.Base.Copy(fn, skip)
if base == nil {
return fn(it)
}
it = &ImaginaryType{Base: base}
if r := fn(it); r != nil {
return r
}
return it
}
func (it *ImaginaryType) GoString() string {
return it.goString(0, "")
}
func (it *ImaginaryType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sImaginaryType:\n%s", indent, "", field,
it.Base.goString(indent+2, ""))
}
// SuffixType is an type with an arbitrary suffix.
type SuffixType struct {
Base AST
Suffix string
}
func (st *SuffixType) print(ps *printState) {
printBase(ps, st, st.Base)
}
func (st *SuffixType) printInner(ps *printState) {
ps.writeByte(' ')
ps.writeString(st.Suffix)
}
func (st *SuffixType) Traverse(fn func(AST) bool) {
if fn(st) {
st.Base.Traverse(fn)
}
}
func (st *SuffixType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(st) {
return nil
}
base := st.Base.Copy(fn, skip)
if base == nil {
return fn(st)
}
st = &SuffixType{Base: base, Suffix: st.Suffix}
if r := fn(st); r != nil {
return r
}
return st
}
func (st *SuffixType) GoString() string {
return st.goString(0, "")
}
func (st *SuffixType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sSuffixType: %s\n%s", indent, "", field,
st.Suffix, st.Base.goString(indent+2, "Base: "))
}
// TransformedType is a builtin type with a template argument.
type TransformedType struct {
Name string
Base AST
}
func (tt *TransformedType) print(ps *printState) {
ps.writeString(tt.Name)
ps.startScope('(')
ps.print(tt.Base)
ps.endScope(')')
}
func (tt *TransformedType) Traverse(fn func(AST) bool) {
if fn(tt) {
tt.Base.Traverse(fn)
}
}
func (tt *TransformedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(tt) {
return nil
}
base := tt.Base.Copy(fn, skip)
if base == nil {
return fn(tt)
}
tt = &TransformedType{Name: tt.Name, Base: base}
if r := fn(tt); r != nil {
return r
}
return tt
}
func (tt *TransformedType) GoString() string {
return tt.goString(0, "")
}
func (tt *TransformedType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTransformedType: %s\n%s", indent, "", field,
tt.Name, tt.Base.goString(indent+2, "Base: "))
}
// VendorQualifier is a type qualified by a vendor-specific qualifier.
type VendorQualifier struct {
Qualifier AST
Type AST
}
func (vq *VendorQualifier) print(ps *printState) {
if ps.llvmStyle {
ps.print(vq.Type)
vq.printInner(ps)
} else {
ps.inner = append(ps.inner, vq)
ps.print(vq.Type)
if len(ps.inner) > 0 {
ps.printOneInner(nil)
}
}
}
func (vq *VendorQualifier) printInner(ps *printState) {
ps.writeByte(' ')
ps.print(vq.Qualifier)
}
func (vq *VendorQualifier) Traverse(fn func(AST) bool) {
if fn(vq) {
vq.Qualifier.Traverse(fn)
vq.Type.Traverse(fn)
}
}
func (vq *VendorQualifier) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(vq) {
return nil
}
qualifier := vq.Qualifier.Copy(fn, skip)
typ := vq.Type.Copy(fn, skip)
if qualifier == nil && typ == nil {
return fn(vq)
}
if qualifier == nil {
qualifier = vq.Qualifier
}
if typ == nil {
typ = vq.Type
}
vq = &VendorQualifier{Qualifier: qualifier, Type: vq.Type}
if r := fn(vq); r != nil {
return r
}
return vq
}
func (vq *VendorQualifier) GoString() string {
return vq.goString(0, "")
}
func (vq *VendorQualifier) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sVendorQualifier:\n%s\n%s", indent, "", field,
vq.Qualifier.goString(indent+2, "Qualifier: "),
vq.Type.goString(indent+2, "Type: "))
}
// ArrayType is an array type.
type ArrayType struct {
Dimension AST
Element AST
}
func (at *ArrayType) print(ps *printState) {
// Pass the array type down as an inner type so that we print
// multi-dimensional arrays correctly.
ps.inner = append(ps.inner, at)
ps.print(at.Element)
if ln := len(ps.inner); ln > 0 {
ps.inner = ps.inner[:ln-1]
at.printDimension(ps)
}
}
func (at *ArrayType) printInner(ps *printState) {
at.printDimension(ps)
}
// Print the array dimension.
func (at *ArrayType) printDimension(ps *printState) {
space := " "
for len(ps.inner) > 0 {
// We haven't gotten to the real type yet. Use
// parentheses around that type, except that if it is
// an array type we print it as a multi-dimensional
// array
in := ps.inner[len(ps.inner)-1]
if twq, ok := in.(*TypeWithQualifiers); ok {
in = twq.Base
}
if _, ok := in.(*ArrayType); ok {
if in == ps.inner[len(ps.inner)-1] {
space = ""
}
ps.printOneInner(nil)
} else {
ps.writeByte(' ')
ps.startScope('(')
ps.printInner(false)
ps.endScope(')')
}
}
ps.writeString(space)
ps.writeByte('[')
ps.print(at.Dimension)
ps.writeByte(']')
}
func (at *ArrayType) Traverse(fn func(AST) bool) {
if fn(at) {
at.Dimension.Traverse(fn)
at.Element.Traverse(fn)
}
}
func (at *ArrayType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(at) {
return nil
}
dimension := at.Dimension.Copy(fn, skip)
element := at.Element.Copy(fn, skip)
if dimension == nil && element == nil {
return fn(at)
}
if dimension == nil {
dimension = at.Dimension
}
if element == nil {
element = at.Element
}
at = &ArrayType{Dimension: dimension, Element: element}
if r := fn(at); r != nil {
return r
}
return at
}
func (at *ArrayType) GoString() string {
return at.goString(0, "")
}
func (at *ArrayType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sArrayType:\n%s\n%s", indent, "", field,
at.Dimension.goString(indent+2, "Dimension: "),
at.Element.goString(indent+2, "Element: "))
}
// FunctionType is a function type.
type FunctionType struct {
Return AST
Args []AST
// The forLocalName field reports whether this FunctionType
// was created for a local name. With the default GNU demangling
// output we don't print the return type in that case.
ForLocalName bool
}
func (ft *FunctionType) print(ps *printState) {
retType := ft.Return
if ft.ForLocalName && (!ps.enclosingParams || !ps.llvmStyle) {
retType = nil
}
if retType != nil {
// Pass the return type as an inner type in order to
// print the arguments in the right location.
ps.inner = append(ps.inner, ft)
ps.print(retType)
if len(ps.inner) == 0 {
// Everything was printed.
return
}
ps.inner = ps.inner[:len(ps.inner)-1]
ps.writeByte(' ')
}
ft.printArgs(ps)
}
func (ft *FunctionType) printInner(ps *printState) {
ft.printArgs(ps)
}
// printArgs prints the arguments of a function type. It looks at the
// inner types for spacing.
func (ft *FunctionType) printArgs(ps *printState) {
paren := false
space := false
for i := len(ps.inner) - 1; i >= 0; i-- {
switch ps.inner[i].(type) {
case *PointerType, *ReferenceType, *RvalueReferenceType:
paren = true
case *TypeWithQualifiers, *ComplexType, *ImaginaryType, *PtrMem:
space = true
paren = true
}
if paren {
break
}
}
if paren {
if !space && (ps.last != '(' && ps.last != '*') {
space = true
}
if space && ps.last != ' ' {
ps.writeByte(' ')
}
ps.startScope('(')
}
save := ps.printInner(true)
if paren {
ps.endScope(')')
}
ps.startScope('(')
if !ft.ForLocalName || ps.enclosingParams {
first := true
for _, a := range ft.Args {
if ps.isEmpty(a) {
continue
}
if !first {
ps.writeString(", ")
}
ps.print(a)
first = false
}
}
ps.endScope(')')
ps.inner = save
ps.printInner(false)
}
func (ft *FunctionType) Traverse(fn func(AST) bool) {
if fn(ft) {
if ft.Return != nil {
ft.Return.Traverse(fn)
}
for _, a := range ft.Args {
a.Traverse(fn)
}
}
}
func (ft *FunctionType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(ft) {
return nil
}
changed := false
var ret AST
if ft.Return != nil {
ret = ft.Return.Copy(fn, skip)
if ret == nil {
ret = ft.Return
} else {
changed = true
}
}
args := make([]AST, len(ft.Args))
for i, a := range ft.Args {
ac := a.Copy(fn, skip)
if ac == nil {
args[i] = a
} else {
args[i] = ac
changed = true
}
}
if !changed {
return fn(ft)
}
ft = &FunctionType{
Return: ret,
Args: args,
ForLocalName: ft.ForLocalName,
}
if r := fn(ft); r != nil {
return r
}
return ft
}
func (ft *FunctionType) GoString() string {
return ft.goString(0, "")
}
func (ft *FunctionType) goString(indent int, field string) string {
var forLocalName string
if ft.ForLocalName {
forLocalName = " ForLocalName: true"
}
var r string
if ft.Return == nil {
r = fmt.Sprintf("%*sReturn: nil", indent+2, "")
} else {
r = ft.Return.goString(indent+2, "Return: ")
}
var args string
if len(ft.Args) == 0 {
args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
} else {
args = fmt.Sprintf("%*sArgs:", indent+2, "")
for i, a := range ft.Args {
args += "\n"
args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
}
}
return fmt.Sprintf("%*s%sFunctionType:%s\n%s\n%s", indent, "", field,
forLocalName, r, args)
}
// FunctionParam is a parameter of a function, used for last-specified
// return type in a closure.
type FunctionParam struct {
Index int
}
func (fp *FunctionParam) print(ps *printState) {
if fp.Index == 0 {
ps.writeString("this")
} else if ps.llvmStyle {
if fp.Index == 1 {
ps.writeString("fp")
} else {
fmt.Fprintf(&ps.buf, "fp%d", fp.Index-2)
}
} else {
fmt.Fprintf(&ps.buf, "{parm#%d}", fp.Index)
}
}
func (fp *FunctionParam) Traverse(fn func(AST) bool) {
fn(fp)
}
func (fp *FunctionParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(fp) {
return nil
}
return fn(fp)
}
func (fp *FunctionParam) GoString() string {
return fp.goString(0, "")
}
func (fp *FunctionParam) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sFunctionParam: %d", indent, "", field, fp.Index)
}
func (fp *FunctionParam) prec() precedence {
return precPrimary
}
// PtrMem is a pointer-to-member expression.
type PtrMem struct {
Class AST
Member AST
}
func (pm *PtrMem) print(ps *printState) {
ps.inner = append(ps.inner, pm)
ps.print(pm.Member)
if len(ps.inner) > 0 {
ps.printOneInner(nil)
}
}
func (pm *PtrMem) printInner(ps *printState) {
if ps.last != '(' {
ps.writeByte(' ')
}
ps.print(pm.Class)
ps.writeString("::*")
}
func (pm *PtrMem) Traverse(fn func(AST) bool) {
if fn(pm) {
pm.Class.Traverse(fn)
pm.Member.Traverse(fn)
}
}
func (pm *PtrMem) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(pm) {
return nil
}
class := pm.Class.Copy(fn, skip)
member := pm.Member.Copy(fn, skip)
if class == nil && member == nil {
return fn(pm)
}
if class == nil {
class = pm.Class
}
if member == nil {
member = pm.Member
}
pm = &PtrMem{Class: class, Member: member}
if r := fn(pm); r != nil {
return r
}
return pm
}
func (pm *PtrMem) GoString() string {
return pm.goString(0, "")
}
func (pm *PtrMem) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sPtrMem:\n%s\n%s", indent, "", field,
pm.Class.goString(indent+2, "Class: "),
pm.Member.goString(indent+2, "Member: "))
}
// FixedType is a fixed numeric type of unknown size.
type FixedType struct {
Base AST
Accum bool
Sat bool
}
func (ft *FixedType) print(ps *printState) {
if ft.Sat {
ps.writeString("_Sat ")
}
if bt, ok := ft.Base.(*BuiltinType); ok && bt.Name == "int" {
// The standard demangler skips printing "int".
} else {
ps.print(ft.Base)
ps.writeByte(' ')
}
if ft.Accum {
ps.writeString("_Accum")
} else {
ps.writeString("_Fract")
}
}
func (ft *FixedType) Traverse(fn func(AST) bool) {
if fn(ft) {
ft.Base.Traverse(fn)
}
}
func (ft *FixedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(ft) {
return nil
}
base := ft.Base.Copy(fn, skip)
if base == nil {
return fn(ft)
}
ft = &FixedType{Base: base, Accum: ft.Accum, Sat: ft.Sat}
if r := fn(ft); r != nil {
return r
}
return ft
}
func (ft *FixedType) GoString() string {
return ft.goString(0, "")
}
func (ft *FixedType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sFixedType: Accum: %t; Sat: %t\n%s", indent, "", field,
ft.Accum, ft.Sat,
ft.Base.goString(indent+2, "Base: "))
}
// BinaryFP is a binary floating-point type.
type BinaryFP struct {
Bits int
Suffix string
}
func (bfp *BinaryFP) print(ps *printState) {
fmt.Fprintf(&ps.buf, "_Float%d%s", bfp.Bits, bfp.Suffix)
}
func (bfp *BinaryFP) Traverse(fn func(AST) bool) {
fn(bfp)
}
func (bfp *BinaryFP) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(bfp) {
return nil
}
return fn(bfp)
}
func (bfp *BinaryFP) GoString() string {
return bfp.goString(0, "")
}
func (bfp *BinaryFP) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sBinaryFP: Bits: %d Suffix: %s", indent, "", field, bfp.Bits, bfp.Suffix)
}
// BitIntType is the C++23 _BitInt(N) type.
type BitIntType struct {
Size AST
Signed bool
}
func (bt *BitIntType) print(ps *printState) {
if !bt.Signed {
ps.writeString("unsigned ")
}
ps.writeString("_BitInt")
ps.startScope('(')
ps.print(bt.Size)
ps.endScope(')')
}
func (bt *BitIntType) Traverse(fn func(AST) bool) {
if fn(bt) {
bt.Size.Traverse(fn)
}
}
func (bt *BitIntType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(bt) {
return nil
}
size := bt.Size.Copy(fn, skip)
if size == nil {
return fn(bt)
}
bt = &BitIntType{Size: size, Signed: bt.Signed}
if r := fn(bt); r != nil {
return r
}
return bt
}
func (bt *BitIntType) GoString() string {
return bt.goString(0, "")
}
func (bt *BitIntType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sBitIntType: Signed: %t\n%s", indent, "", field,
bt.Signed,
bt.Size.goString(indent+2, "Size: "))
}
// VectorType is a vector type.
type VectorType struct {
Dimension AST
Base AST
}
func (vt *VectorType) print(ps *printState) {
ps.inner = append(ps.inner, vt)
ps.print(vt.Base)
if len(ps.inner) > 0 {
ps.printOneInner(nil)
}
}
func (vt *VectorType) printInner(ps *printState) {
end := byte(')')
if ps.llvmStyle {
ps.writeString(" vector[")
end = ']'
} else {
ps.writeString(" __vector(")
}
ps.print(vt.Dimension)
ps.writeByte(end)
}
func (vt *VectorType) Traverse(fn func(AST) bool) {
if fn(vt) {
vt.Dimension.Traverse(fn)
vt.Base.Traverse(fn)
}
}
func (vt *VectorType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(vt) {
return nil
}
dimension := vt.Dimension.Copy(fn, skip)
base := vt.Base.Copy(fn, skip)
if dimension == nil && base == nil {
return fn(vt)
}
if dimension == nil {
dimension = vt.Dimension
}
if base == nil {
base = vt.Base
}
vt = &VectorType{Dimension: dimension, Base: base}
if r := fn(vt); r != nil {
return r
}
return vt
}
func (vt *VectorType) GoString() string {
return vt.goString(0, "")
}
func (vt *VectorType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sVectorType:\n%s\n%s", indent, "", field,
vt.Dimension.goString(indent+2, "Dimension: "),
vt.Base.goString(indent+2, "Base: "))
}
// ElaboratedType is an elaborated struct/union/enum type.
type ElaboratedType struct {
Kind string
Type AST
}
func (et *ElaboratedType) print(ps *printState) {
ps.writeString(et.Kind)
ps.writeString(" ")
et.Type.print(ps)
}
func (et *ElaboratedType) Traverse(fn func(AST) bool) {
if fn(et) {
et.Type.Traverse(fn)
}
}
func (et *ElaboratedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(et) {
return nil
}
typ := et.Type.Copy(fn, skip)
if typ == nil {
return fn(et)
}
et = &ElaboratedType{Kind: et.Kind, Type: typ}
if r := fn(et); r != nil {
return r
}
return et
}
func (et *ElaboratedType) GoString() string {
return et.goString(0, "")
}
func (et *ElaboratedType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sElaboratedtype: Kind: %s\n%s", indent, "", field,
et.Kind, et.Type.goString(indent+2, "Expr: "))
}
// Decltype is the decltype operator.
type Decltype struct {
Expr AST
}
func (dt *Decltype) print(ps *printState) {
ps.writeString("decltype")
if !ps.llvmStyle {
ps.writeString(" ")
}
ps.startScope('(')
ps.print(dt.Expr)
ps.endScope(')')
}
func (dt *Decltype) Traverse(fn func(AST) bool) {
if fn(dt) {
dt.Expr.Traverse(fn)
}
}
func (dt *Decltype) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(dt) {
return nil
}
expr := dt.Expr.Copy(fn, skip)
if expr == nil {
return fn(dt)
}
dt = &Decltype{Expr: expr}
if r := fn(dt); r != nil {
return r
}
return dt
}
func (dt *Decltype) GoString() string {
return dt.goString(0, "")
}
func (dt *Decltype) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sDecltype:\n%s", indent, "", field,
dt.Expr.goString(indent+2, "Expr: "))
}
// Operator is an operator.
type Operator struct {
Name string
precedence precedence
}
func (op *Operator) print(ps *printState) {
ps.writeString("operator")
if isLower(op.Name[0]) {
ps.writeByte(' ')
}
n := op.Name
n = strings.TrimSuffix(n, " ")
ps.writeString(n)
}
func (op *Operator) Traverse(fn func(AST) bool) {
fn(op)
}
func (op *Operator) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(op) {
return nil
}
return fn(op)
}
func (op *Operator) GoString() string {
return op.goString(0, "")
}
func (op *Operator) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sOperator: %s", indent, "", field, op.Name)
}
func (op *Operator) prec() precedence {
return op.precedence
}
// Constructor is a constructor.
type Constructor struct {
Name AST
Base AST // base class of inheriting constructor
}
func (c *Constructor) print(ps *printState) {
ps.print(c.Name)
// We don't include the base class in the demangled string.
}
func (c *Constructor) Traverse(fn func(AST) bool) {
if fn(c) {
c.Name.Traverse(fn)
if c.Base != nil {
c.Base.Traverse(fn)
}
}
}
func (c *Constructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(c) {
return nil
}
name := c.Name.Copy(fn, skip)
var base AST
if c.Base != nil {
base = c.Base.Copy(fn, skip)
}
if name == nil && base == nil {
return fn(c)
}
if name == nil {
name = c.Name
}
if base == nil {
base = c.Base
}
c = &Constructor{Name: name, Base: base}
if r := fn(c); r != nil {
return r
}
return c
}
func (c *Constructor) GoString() string {
return c.goString(0, "")
}
func (c *Constructor) goString(indent int, field string) string {
var sb strings.Builder
fmt.Fprintf(&sb, "%*s%sConstructor:\n", indent, "", field)
if c.Base != nil {
fmt.Fprintf(&sb, "%s\n", c.Base.goString(indent+2, "Base: "))
}
fmt.Fprintf(&sb, "%s", c.Name.goString(indent+2, "Name: "))
return sb.String()
}
// Destructor is a destructor.
type Destructor struct {
Name AST
}
func (d *Destructor) print(ps *printState) {
ps.writeByte('~')
ps.print(d.Name)
}
func (d *Destructor) Traverse(fn func(AST) bool) {
if fn(d) {
d.Name.Traverse(fn)
}
}
func (d *Destructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(d) {
return nil
}
name := d.Name.Copy(fn, skip)
if name == nil {
return fn(d)
}
d = &Destructor{Name: name}
if r := fn(d); r != nil {
return r
}
return d
}
func (d *Destructor) GoString() string {
return d.goString(0, "")
}
func (d *Destructor) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sDestructor:\n%s", indent, "", field, d.Name.goString(indent+2, "Name: "))
}
// GlobalCDtor is a global constructor or destructor.
type GlobalCDtor struct {
Ctor bool
Key AST
}
func (gcd *GlobalCDtor) print(ps *printState) {
ps.writeString("global ")
if gcd.Ctor {
ps.writeString("constructors")
} else {
ps.writeString("destructors")
}
ps.writeString(" keyed to ")
ps.print(gcd.Key)
}
func (gcd *GlobalCDtor) Traverse(fn func(AST) bool) {
if fn(gcd) {
gcd.Key.Traverse(fn)
}
}
func (gcd *GlobalCDtor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(gcd) {
return nil
}
key := gcd.Key.Copy(fn, skip)
if key == nil {
return fn(gcd)
}
gcd = &GlobalCDtor{Ctor: gcd.Ctor, Key: key}
if r := fn(gcd); r != nil {
return r
}
return gcd
}
func (gcd *GlobalCDtor) GoString() string {
return gcd.goString(0, "")
}
func (gcd *GlobalCDtor) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sGlobalCDtor: Ctor: %t\n%s", indent, "", field,
gcd.Ctor, gcd.Key.goString(indent+2, "Key: "))
}
// TaggedName is a name with an ABI tag.
type TaggedName struct {
Name AST
Tag AST
}
func (t *TaggedName) print(ps *printState) {
ps.print(t.Name)
ps.writeString("[abi:")
ps.print(t.Tag)
ps.writeByte(']')
}
func (t *TaggedName) Traverse(fn func(AST) bool) {
if fn(t) {
t.Name.Traverse(fn)
t.Tag.Traverse(fn)
}
}
func (t *TaggedName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(t) {
return nil
}
name := t.Name.Copy(fn, skip)
tag := t.Tag.Copy(fn, skip)
if name == nil && tag == nil {
return fn(t)
}
if name == nil {
name = t.Name
}
if tag == nil {
tag = t.Tag
}
t = &TaggedName{Name: name, Tag: tag}
if r := fn(t); r != nil {
return r
}
return t
}
func (t *TaggedName) GoString() string {
return t.goString(0, "")
}
func (t *TaggedName) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTaggedName:\n%s\n%s", indent, "", field,
t.Name.goString(indent+2, "Name: "),
t.Tag.goString(indent+2, "Tag: "))
}
// PackExpansion is a pack expansion. The Pack field may be nil.
type PackExpansion struct {
Base AST
Pack *ArgumentPack
}
func (pe *PackExpansion) print(ps *printState) {
// We normally only get here if the simplify function was
// unable to locate and expand the pack.
if pe.Pack == nil {
if ps.llvmStyle {
ps.print(pe.Base)
} else {
parenthesize(ps, pe.Base)
ps.writeString("...")
}
} else {
ps.print(pe.Base)
}
}
func (pe *PackExpansion) Traverse(fn func(AST) bool) {
if fn(pe) {
pe.Base.Traverse(fn)
// Don't traverse Template--it points elsewhere in the AST.
}
}
func (pe *PackExpansion) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(pe) {
return nil
}
base := pe.Base.Copy(fn, skip)
if base == nil {
return fn(pe)
}
pe = &PackExpansion{Base: base, Pack: pe.Pack}
if r := fn(pe); r != nil {
return r
}
return pe
}
func (pe *PackExpansion) GoString() string {
return pe.goString(0, "")
}
func (pe *PackExpansion) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sPackExpansion: Pack: %p\n%s", indent, "", field,
pe.Pack, pe.Base.goString(indent+2, "Base: "))
}
// ArgumentPack is an argument pack.
type ArgumentPack struct {
Args []AST
}
func (ap *ArgumentPack) print(ps *printState) {
for i, a := range ap.Args {
if i > 0 {
ps.writeString(", ")
}
ps.print(a)
}
}
func (ap *ArgumentPack) Traverse(fn func(AST) bool) {
if fn(ap) {
for _, a := range ap.Args {
a.Traverse(fn)
}
}
}
func (ap *ArgumentPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(ap) {
return nil
}
args := make([]AST, len(ap.Args))
changed := false
for i, a := range ap.Args {
ac := a.Copy(fn, skip)
if ac == nil {
args[i] = a
} else {
args[i] = ac
changed = true
}
}
if !changed {
return fn(ap)
}
ap = &ArgumentPack{Args: args}
if r := fn(ap); r != nil {
return r
}
return ap
}
func (ap *ArgumentPack) GoString() string {
return ap.goString(0, "")
}
func (ap *ArgumentPack) goString(indent int, field string) string {
if len(ap.Args) == 0 {
return fmt.Sprintf("%*s%sArgumentPack: nil", indent, "", field)
}
s := fmt.Sprintf("%*s%sArgumentPack:", indent, "", field)
for i, a := range ap.Args {
s += "\n"
s += a.goString(indent+2, fmt.Sprintf("%d: ", i))
}
return s
}
// SizeofPack is the sizeof operator applied to an argument pack.
type SizeofPack struct {
Pack *ArgumentPack
}
func (sp *SizeofPack) print(ps *printState) {
if ps.llvmStyle {
ps.writeString("sizeof...")
ps.startScope('(')
ps.print(sp.Pack)
ps.endScope(')')
} else {
ps.writeString(fmt.Sprintf("%d", len(sp.Pack.Args)))
}
}
func (sp *SizeofPack) Traverse(fn func(AST) bool) {
fn(sp)
// Don't traverse the pack--it points elsewhere in the AST.
}
func (sp *SizeofPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(sp) {
return nil
}
sp = &SizeofPack{Pack: sp.Pack}
if r := fn(sp); r != nil {
return r
}
return sp
}
func (sp *SizeofPack) GoString() string {
return sp.goString(0, "")
}
func (sp *SizeofPack) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sSizeofPack: Pack: %p", indent, "", field, sp.Pack)
}
// SizeofArgs is the size of a captured template parameter pack from
// an alias template.
type SizeofArgs struct {
Args []AST
}
func (sa *SizeofArgs) print(ps *printState) {
c := 0
for _, a := range sa.Args {
if ap, ok := a.(*ArgumentPack); ok {
c += len(ap.Args)
} else if el, ok := a.(*ExprList); ok {
c += len(el.Exprs)
} else {
c++
}
}
ps.writeString(fmt.Sprintf("%d", c))
}
func (sa *SizeofArgs) Traverse(fn func(AST) bool) {
if fn(sa) {
for _, a := range sa.Args {
a.Traverse(fn)
}
}
}
func (sa *SizeofArgs) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(sa) {
return nil
}
changed := false
args := make([]AST, len(sa.Args))
for i, a := range sa.Args {
ac := a.Copy(fn, skip)
if ac == nil {
args[i] = a
} else {
args[i] = ac
changed = true
}
}
if !changed {
return fn(sa)
}
sa = &SizeofArgs{Args: args}
if r := fn(sa); r != nil {
return r
}
return sa
}
func (sa *SizeofArgs) GoString() string {
return sa.goString(0, "")
}
func (sa *SizeofArgs) goString(indent int, field string) string {
var args string
if len(sa.Args) == 0 {
args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
} else {
args = fmt.Sprintf("%*sArgs:", indent+2, "")
for i, a := range sa.Args {
args += "\n"
args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
}
}
return fmt.Sprintf("%*s%sSizeofArgs:\n%s", indent, "", field, args)
}
// TemplateParamName is the name of a template parameter that the
// demangler introduced for a lambda that has explicit template
// parameters. This is a prefix with an index.
type TemplateParamName struct {
Prefix string
Index int
}
func (tpn *TemplateParamName) print(ps *printState) {
ps.writeString(tpn.Prefix)
if ps.llvmStyle {
if tpn.Index > 0 {
ps.writeString(fmt.Sprintf("%d", tpn.Index-1))
}
} else {
ps.writeString(fmt.Sprintf("%d", tpn.Index))
}
}
func (tpn *TemplateParamName) Traverse(fn func(AST) bool) {
fn(tpn)
}
func (tpn *TemplateParamName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(tpn) {
return nil
}
return fn(tpn)
}
func (tpn *TemplateParamName) GoString() string {
return tpn.goString(0, "")
}
func (tpn *TemplateParamName) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTemplateParamName: %s%d", indent, "", field, tpn.Prefix, tpn.Index)
}
// TypeTemplateParam is a type template parameter that appears in a
// lambda with explicit template parameters.
type TypeTemplateParam struct {
Name AST
}
func (ttp *TypeTemplateParam) print(ps *printState) {
ps.writeString("typename")
if ps.llvmStyle {
ps.writeByte(' ')
}
ps.printInner(false)
if ps.llvmStyle || !ps.lambdaTemplateArgs {
if !ps.llvmStyle {
ps.writeByte(' ')
}
ps.print(ttp.Name)
}
}
func (ttp *TypeTemplateParam) Traverse(fn func(AST) bool) {
if fn(ttp) {
ttp.Name.Traverse(fn)
}
}
func (ttp *TypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(ttp) {
return nil
}
name := ttp.Name.Copy(fn, skip)
if name == nil {
return fn(ttp)
}
ttp = &TypeTemplateParam{Name: name}
if r := fn(ttp); r != nil {
return r
}
return ttp
}
func (ttp *TypeTemplateParam) GoString() string {
return ttp.goString(0, "")
}
func (ttp *TypeTemplateParam) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTypeTemplateParam:\n%s", indent, "", field,
ttp.Name.goString(indent+2, "Name"))
}
// NonTypeTemplateParam is a non-type template parameter that appears
// in a lambda with explicit template parameters.
type NonTypeTemplateParam struct {
Name AST
Type AST
}
func (nttp *NonTypeTemplateParam) print(ps *printState) {
ps.inner = append(ps.inner, nttp)
ps.print(nttp.Type)
if len(ps.inner) > 0 {
if ps.llvmStyle || !ps.lambdaTemplateArgs {
ps.writeByte(' ')
ps.print(nttp.Name)
}
ps.inner = ps.inner[:len(ps.inner)-1]
}
}
func (nttp *NonTypeTemplateParam) printInner(ps *printState) {
ps.print(nttp.Name)
}
func (nttp *NonTypeTemplateParam) Traverse(fn func(AST) bool) {
if fn(nttp) {
nttp.Name.Traverse(fn)
nttp.Type.Traverse(fn)
}
}
func (nttp *NonTypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(nttp) {
return nil
}
name := nttp.Name.Copy(fn, skip)
typ := nttp.Type.Copy(fn, skip)
if name == nil && typ == nil {
return fn(nttp)
}
if name == nil {
name = nttp.Name
}
if typ == nil {
typ = nttp.Type
}
nttp = &NonTypeTemplateParam{Name: name, Type: typ}
if r := fn(nttp); r != nil {
return r
}
return nttp
}
func (nttp *NonTypeTemplateParam) GoString() string {
return nttp.goString(0, "")
}
func (nttp *NonTypeTemplateParam) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sNonTypeTemplateParam:\n%s\n%s", indent, "", field,
nttp.Name.goString(indent+2, "Name: "),
nttp.Type.goString(indent+2, "Type: "))
}
// TemplateTemplateParam is a template template parameter that appears
// in a lambda with explicit template parameters.
type TemplateTemplateParam struct {
Name AST
Params []AST
Constraint AST
}
func (ttp *TemplateTemplateParam) print(ps *printState) {
scopes := ps.scopes
ps.scopes = 0
lambdaTemplateArgs := ps.lambdaTemplateArgs
ps.lambdaTemplateArgs = true
inner := ps.inner
ps.inner = nil
ps.writeString("template<")
ps.printList(ttp.Params, nil)
ps.writeString("> ")
if ps.llvmStyle {
ps.writeString("typename")
} else {
ps.writeString("class")
}
ps.scopes = scopes
ps.lambdaTemplateArgs = lambdaTemplateArgs
ps.inner = inner
ps.printInner(false)
if ps.llvmStyle || !ps.lambdaTemplateArgs {
ps.writeByte(' ')
ps.print(ttp.Name)
}
if ttp.Constraint != nil {
ps.writeString(" requires ")
ps.print(ttp.Constraint)
}
}
func (ttp *TemplateTemplateParam) Traverse(fn func(AST) bool) {
if fn(ttp) {
ttp.Name.Traverse(fn)
for _, param := range ttp.Params {
param.Traverse(fn)
}
if ttp.Constraint != nil {
ttp.Constraint.Traverse(fn)
}
}
}
func (ttp *TemplateTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(ttp) {
return nil
}
changed := false
name := ttp.Name.Copy(fn, skip)
if name == nil {
name = ttp.Name
} else {
changed = true
}
params := make([]AST, len(ttp.Params))
for i, p := range ttp.Params {
pc := p.Copy(fn, skip)
if pc == nil {
params[i] = p
} else {
params[i] = pc
changed = true
}
}
var constraint AST
if ttp.Constraint != nil {
constraint = ttp.Constraint.Copy(fn, skip)
if constraint == nil {
constraint = ttp.Constraint
} else {
changed = true
}
}
if !changed {
return fn(ttp)
}
ttp = &TemplateTemplateParam{
Name: name,
Params: params,
Constraint: constraint,
}
if r := fn(ttp); r != nil {
return r
}
return ttp
}
func (ttp *TemplateTemplateParam) GoString() string {
return ttp.goString(0, "")
}
func (ttp *TemplateTemplateParam) goString(indent int, field string) string {
var params strings.Builder
fmt.Fprintf(¶ms, "%*sParams:", indent+2, "")
for i, p := range ttp.Params {
params.WriteByte('\n')
params.WriteString(p.goString(indent+4, fmt.Sprintf("%d: ", i)))
}
var constraint string
if ttp.Constraint == nil {
constraint = fmt.Sprintf("%*sConstraint: nil", indent+2, "")
} else {
constraint = ttp.Constraint.goString(indent+2, "Constraint: ")
}
return fmt.Sprintf("%*s%sTemplateTemplateParam:\n%s\n%s\n%s", indent, "", field,
ttp.Name.goString(indent+2, "Name: "),
params.String(),
constraint)
}
// ConstrainedTypeTemplateParam is a constrained template type
// parameter declaration.
type ConstrainedTypeTemplateParam struct {
Name AST
Constraint AST
}
func (cttp *ConstrainedTypeTemplateParam) print(ps *printState) {
ps.inner = append(ps.inner, cttp)
ps.print(cttp.Constraint)
if len(ps.inner) > 0 {
ps.writeByte(' ')
ps.print(cttp.Name)
ps.inner = ps.inner[:len(ps.inner)-1]
}
}
func (cttp *ConstrainedTypeTemplateParam) printInner(ps *printState) {
ps.print(cttp.Name)
}
func (cttp *ConstrainedTypeTemplateParam) Traverse(fn func(AST) bool) {
if fn(cttp) {
cttp.Name.Traverse(fn)
cttp.Constraint.Traverse(fn)
}
}
func (cttp *ConstrainedTypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(cttp) {
return nil
}
name := cttp.Name.Copy(fn, skip)
constraint := cttp.Constraint.Copy(fn, skip)
if name == nil && constraint == nil {
return fn(cttp)
}
if name == nil {
name = cttp.Name
}
if constraint == nil {
constraint = cttp.Constraint
}
cttp = &ConstrainedTypeTemplateParam{Name: name, Constraint: constraint}
if r := fn(cttp); r != nil {
return r
}
return cttp
}
func (cttp *ConstrainedTypeTemplateParam) GoString() string {
return cttp.goString(0, "")
}
func (cttp *ConstrainedTypeTemplateParam) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sConstrainedTypeTemplateParam\n%s\n%s", indent, "", field,
cttp.Name.goString(indent+2, "Name: "),
cttp.Constraint.goString(indent+2, "Constraint: "))
}
// TemplateParamPack is a template parameter pack that appears in a
// lambda with explicit template parameters.
type TemplateParamPack struct {
Param AST
}
func (tpp *TemplateParamPack) print(ps *printState) {
holdInner := ps.inner
defer func() { ps.inner = holdInner }()
ps.inner = []AST{tpp}
nttp, isNTTP := tpp.Param.(*NonTypeTemplateParam)
if isNTTP {
ps.print(nttp.Type)
} else {
ps.print(tpp.Param)
}
if len(ps.inner) > 0 {
ps.writeString("...")
if isNTTP && (ps.llvmStyle || !ps.lambdaTemplateArgs) {
ps.writeByte(' ')
ps.print(nttp.Name)
}
}
}
func (tpp *TemplateParamPack) printInner(ps *printState) {
ps.writeString("...")
if nttp, ok := tpp.Param.(*NonTypeTemplateParam); ok {
ps.print(nttp.Name)
}
}
func (tpp *TemplateParamPack) Traverse(fn func(AST) bool) {
if fn(tpp) {
tpp.Param.Traverse(fn)
}
}
func (tpp *TemplateParamPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(tpp) {
return nil
}
param := tpp.Param.Copy(fn, skip)
if param == nil {
return fn(tpp)
}
tpp = &TemplateParamPack{Param: param}
if r := fn(tpp); r != nil {
return r
}
return tpp
}
func (tpp *TemplateParamPack) GoString() string {
return tpp.goString(0, "")
}
func (tpp *TemplateParamPack) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTemplateParamPack:\n%s", indent, "", field,
tpp.Param.goString(indent+2, "Param: "))
}
// Cast is a type cast.
type Cast struct {
To AST
}
func (c *Cast) print(ps *printState) {
ps.writeString("operator ")
ps.print(c.To)
}
func (c *Cast) Traverse(fn func(AST) bool) {
if fn(c) {
c.To.Traverse(fn)
}
}
func (c *Cast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(c) {
return nil
}
to := c.To.Copy(fn, skip)
if to == nil {
return fn(c)
}
c = &Cast{To: to}
if r := fn(c); r != nil {
return r
}
return c
}
func (c *Cast) GoString() string {
return c.goString(0, "")
}
func (c *Cast) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sCast\n%s", indent, "", field,
c.To.goString(indent+2, "To: "))
}
func (c *Cast) prec() precedence {
return precCast
}
// The parenthesize function prints the string for val, wrapped in
// parentheses if necessary.
func parenthesize(ps *printState, val AST) {
paren := false
switch v := val.(type) {
case *Name, *InitializerList:
case *FunctionParam:
if ps.llvmStyle {
paren = true
}
case *Qualified:
if v.LocalName {
paren = true
}
default:
paren = true
}
if paren {
ps.startScope('(')
}
ps.print(val)
if paren {
ps.endScope(')')
}
}
// Nullary is an operator in an expression with no arguments, such as
// throw.
type Nullary struct {
Op AST
}
func (n *Nullary) print(ps *printState) {
if op, ok := n.Op.(*Operator); ok {
ps.writeString(op.Name)
} else {
ps.print(n.Op)
}
}
func (n *Nullary) Traverse(fn func(AST) bool) {
if fn(n) {
n.Op.Traverse(fn)
}
}
func (n *Nullary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(n) {
return nil
}
op := n.Op.Copy(fn, skip)
if op == nil {
return fn(n)
}
n = &Nullary{Op: op}
if r := fn(n); r != nil {
return r
}
return n
}
func (n *Nullary) GoString() string {
return n.goString(0, "")
}
func (n *Nullary) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sNullary:\n%s", indent, "", field,
n.Op.goString(indent+2, "Op: "))
}
// Unary is a unary operation in an expression.
type Unary struct {
Op AST
Expr AST
Suffix bool // true for ++ -- when used as postfix
SizeofType bool // true for sizeof (type)
}
func (u *Unary) print(ps *printState) {
op, _ := u.Op.(*Operator)
expr := u.Expr
// Don't print the argument list when taking the address of a
// function.
if !ps.llvmStyle {
if op != nil && op.Name == "&" {
if t, ok := expr.(*Typed); ok {
if _, ok := t.Type.(*FunctionType); ok {
expr = t.Name
}
}
}
}
if u.Suffix {
if ps.llvmStyle {
wantParens := true
opPrec := precUnary
if op != nil {
opPrec = op.precedence
}
if p, ok := expr.(hasPrec); ok {
if p.prec() < opPrec {
wantParens = false
}
}
if wantParens {
ps.startScope('(')
}
ps.print(expr)
if wantParens {
ps.endScope(')')
}
} else {
parenthesize(ps, expr)
}
}
if op != nil {
ps.writeString(op.Name)
if ps.llvmStyle && op.Name == "noexcept" {
ps.writeByte(' ')
}
} else if c, ok := u.Op.(*Cast); ok {
ps.startScope('(')
ps.print(c.To)
ps.endScope(')')
} else {
ps.print(u.Op)
}
if !u.Suffix {
alwaysParens := u.SizeofType || (op != nil && (op.Name == "__alignof__" || op.Name == "noexcept"))
if op != nil && op.Name == "::" {
// Don't use parentheses after ::.
ps.print(expr)
} else if alwaysParens {
ps.startScope('(')
ps.print(expr)
ps.endScope(')')
} else if ps.llvmStyle {
var wantParens bool
switch {
case op == nil:
wantParens = true
case op.Name == `operator"" `:
wantParens = false
case op.Name == "&":
wantParens = false
case op.Name == "delete" || op.Name == "delete[]":
wantParens = false
case op.Name == "alignof ":
wantParens = true
case op.Name == "sizeof ":
wantParens = true
case op.Name == "typeid ":
wantParens = true
default:
wantParens = true
if p, ok := expr.(hasPrec); ok {
if p.prec() < op.precedence {
wantParens = false
}
}
}
if wantParens {
ps.startScope('(')
}
ps.print(expr)
if wantParens {
ps.endScope(')')
}
} else {
parenthesize(ps, expr)
}
}
}
func (u *Unary) Traverse(fn func(AST) bool) {
if fn(u) {
u.Op.Traverse(fn)
u.Expr.Traverse(fn)
}
}
func (u *Unary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(u) {
return nil
}
op := u.Op.Copy(fn, skip)
expr := u.Expr.Copy(fn, skip)
if op == nil && expr == nil {
return fn(u)
}
if op == nil {
op = u.Op
}
if expr == nil {
expr = u.Expr
}
u = &Unary{Op: op, Expr: expr, Suffix: u.Suffix, SizeofType: u.SizeofType}
if r := fn(u); r != nil {
return r
}
return u
}
func (u *Unary) GoString() string {
return u.goString(0, "")
}
func (u *Unary) goString(indent int, field string) string {
var s string
if u.Suffix {
s = " Suffix: true"
}
if u.SizeofType {
s += " SizeofType: true"
}
return fmt.Sprintf("%*s%sUnary:%s\n%s\n%s", indent, "", field,
s, u.Op.goString(indent+2, "Op: "),
u.Expr.goString(indent+2, "Expr: "))
}
func (u *Unary) prec() precedence {
if p, ok := u.Op.(hasPrec); ok {
return p.prec()
}
return precDefault
}
// isDesignatedInitializer reports whether x is a designated
// initializer.
func isDesignatedInitializer(x AST) bool {
switch x := x.(type) {
case *Binary:
if op, ok := x.Op.(*Operator); ok {
if op.Name == "]=" {
return true
}
if op.Name != "=" {
return false
}
if _, ok := x.Left.(*Literal); ok {
return false
}
return true
}
case *Trinary:
if op, ok := x.Op.(*Operator); ok {
return op.Name == "[...]="
}
}
return false
}
// Binary is a binary operation in an expression.
type Binary struct {
Op AST
Left AST
Right AST
}
func (b *Binary) print(ps *printState) {
op, _ := b.Op.(*Operator)
if op != nil && strings.Contains(op.Name, "cast") {
ps.writeString(op.Name)
scopes := ps.scopes
ps.scopes = 0
ps.writeByte('<')
ps.print(b.Left)
ps.writeString(">")
ps.scopes = scopes
ps.startScope('(')
ps.print(b.Right)
ps.endScope(')')
return
}
if isDesignatedInitializer(b) {
if op.Name == "=" {
ps.writeByte('.')
} else {
ps.writeByte('[')
}
ps.print(b.Left)
if op.Name == "]=" {
ps.writeByte(']')
}
if isDesignatedInitializer(b.Right) {
// Don't add anything between designated
// initializer chains.
ps.print(b.Right)
} else {
if ps.llvmStyle {
ps.writeString(" = ")
ps.print(b.Right)
} else {
ps.writeByte('=')
parenthesize(ps, b.Right)
}
}
return
}
// Use an extra set of parentheses around an expression that
// uses the greater-than operator, so that it does not get
// confused with the '>' that ends template parameters.
needsOuterParen := op != nil && (op.Name == ">" || op.Name == ">>")
if ps.llvmStyle && ps.scopes > 0 {
needsOuterParen = false
}
if needsOuterParen {
ps.startScope('(')
}
left := b.Left
skipParens := false
addSpaces := ps.llvmStyle
if ps.llvmStyle && op != nil {
switch op.Name {
case ".", "->", "->*":
addSpaces = false
}
}
// For a function call in an expression, don't print the types
// of the arguments unless there is a return type.
if op != nil && strings.HasPrefix(op.Name, "()") {
if ty, ok := b.Left.(*Typed); ok {
if ft, ok := ty.Type.(*FunctionType); ok {
if ft.Return == nil {
left = ty.Name
} else {
if op.Name != "() " {
skipParens = true
}
}
} else {
left = ty.Name
}
}
if ps.llvmStyle && op.Name != "() " {
skipParens = true
}
}
if skipParens {
ps.print(left)
} else if ps.llvmStyle {
prec := precPrimary
if p, ok := left.(hasPrec); ok {
prec = p.prec()
}
needsParen := op.Name == "() "
if prec > b.prec() {
needsParen = true
}
if needsParen {
ps.startScope('(')
}
ps.print(left)
if needsParen {
ps.endScope(')')
}
} else {
parenthesize(ps, left)
}
if op != nil && op.Name == "[]" {
ps.writeByte('[')
ps.print(b.Right)
ps.writeByte(']')
return
}
if op != nil {
if !strings.HasPrefix(op.Name, "()") {
if addSpaces && op.Name != "," {
ps.writeByte(' ')
}
ps.writeString(op.Name)
if addSpaces {
ps.writeByte(' ')
}
}
} else {
ps.print(b.Op)
}
if ps.llvmStyle {
prec := precPrimary
if p, ok := b.Right.(hasPrec); ok {
prec = p.prec()
}
needsParen := false
if prec >= b.prec() {
needsParen = true
}
if needsParen {
ps.startScope('(')
}
ps.print(b.Right)
if needsParen {
ps.endScope(')')
}
} else {
parenthesize(ps, b.Right)
}
if needsOuterParen {
ps.endScope(')')
}
}
func (b *Binary) Traverse(fn func(AST) bool) {
if fn(b) {
b.Op.Traverse(fn)
b.Left.Traverse(fn)
b.Right.Traverse(fn)
}
}
func (b *Binary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(b) {
return nil
}
op := b.Op.Copy(fn, skip)
left := b.Left.Copy(fn, skip)
right := b.Right.Copy(fn, skip)
if op == nil && left == nil && right == nil {
return fn(b)
}
if op == nil {
op = b.Op
}
if left == nil {
left = b.Left
}
if right == nil {
right = b.Right
}
b = &Binary{Op: op, Left: left, Right: right}
if r := fn(b); r != nil {
return r
}
return b
}
func (b *Binary) GoString() string {
return b.goString(0, "")
}
func (b *Binary) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sBinary:\n%s\n%s\n%s", indent, "", field,
b.Op.goString(indent+2, "Op: "),
b.Left.goString(indent+2, "Left: "),
b.Right.goString(indent+2, "Right: "))
}
func (b *Binary) prec() precedence {
if p, ok := b.Op.(hasPrec); ok {
return p.prec()
}
return precDefault
}
// Trinary is the ?: trinary operation in an expression.
type Trinary struct {
Op AST
First AST
Second AST
Third AST
}
func (t *Trinary) print(ps *printState) {
if isDesignatedInitializer(t) {
ps.writeByte('[')
ps.print(t.First)
ps.writeString(" ... ")
ps.print(t.Second)
ps.writeByte(']')
if isDesignatedInitializer(t.Third) {
// Don't add anything between designated
// initializer chains.
ps.print(t.Third)
} else {
if ps.llvmStyle {
ps.writeString(" = ")
ps.print(t.Third)
} else {
ps.writeByte('=')
parenthesize(ps, t.Third)
}
}
return
}
if ps.llvmStyle {
wantParens := true
opPrec := precPrimary
if op, ok := t.Op.(*Operator); ok {
opPrec = op.precedence
}
if p, ok := t.First.(hasPrec); ok {
if p.prec() < opPrec {
wantParens = false
}
}
if wantParens {
ps.startScope('(')
}
ps.print(t.First)
if wantParens {
ps.endScope(')')
}
} else {
parenthesize(ps, t.First)
}
if ps.llvmStyle {
ps.writeString(" ? ")
} else {
ps.writeByte('?')
}
if ps.llvmStyle {
wantParens := true
if p, ok := t.Second.(hasPrec); ok {
if p.prec() < precDefault {
wantParens = false
}
}
if wantParens {
ps.startScope('(')
}
ps.print(t.Second)
if wantParens {
ps.endScope(')')
}
} else {
parenthesize(ps, t.Second)
}
ps.writeString(" : ")
if ps.llvmStyle {
wantParens := true
if p, ok := t.Third.(hasPrec); ok {
if p.prec() < precAssign {
wantParens = false
}
}
if wantParens {
ps.startScope('(')
}
ps.print(t.Third)
if wantParens {
ps.endScope(')')
}
} else {
parenthesize(ps, t.Third)
}
}
func (t *Trinary) Traverse(fn func(AST) bool) {
if fn(t) {
t.Op.Traverse(fn)
t.First.Traverse(fn)
t.Second.Traverse(fn)
t.Third.Traverse(fn)
}
}
func (t *Trinary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(t) {
return nil
}
op := t.Op.Copy(fn, skip)
first := t.First.Copy(fn, skip)
second := t.Second.Copy(fn, skip)
third := t.Third.Copy(fn, skip)
if op == nil && first == nil && second == nil && third == nil {
return fn(t)
}
if op == nil {
op = t.Op
}
if first == nil {
first = t.First
}
if second == nil {
second = t.Second
}
if third == nil {
third = t.Third
}
t = &Trinary{Op: op, First: first, Second: second, Third: third}
if r := fn(t); r != nil {
return r
}
return t
}
func (t *Trinary) GoString() string {
return t.goString(0, "")
}
func (t *Trinary) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTrinary:\n%s\n%s\n%s\n%s", indent, "", field,
t.Op.goString(indent+2, "Op: "),
t.First.goString(indent+2, "First: "),
t.Second.goString(indent+2, "Second: "),
t.Third.goString(indent+2, "Third: "))
}
// Fold is a C++17 fold-expression. Arg2 is nil for a unary operator.
type Fold struct {
Left bool
Op AST
Arg1 AST
Arg2 AST
}
func (f *Fold) print(ps *printState) {
op, _ := f.Op.(*Operator)
printOp := func() {
if op != nil {
if ps.llvmStyle {
ps.writeByte(' ')
}
ps.writeString(op.Name)
if ps.llvmStyle {
ps.writeByte(' ')
}
} else {
ps.print(f.Op)
}
}
foldParenthesize := func(a AST) {
if ps.llvmStyle {
prec := precDefault
if p, ok := a.(hasPrec); ok {
prec = p.prec()
}
needsParen := false
if prec > precCast {
needsParen = true
}
if needsParen {
ps.startScope('(')
}
ps.print(a)
if needsParen {
ps.endScope(')')
}
} else {
parenthesize(ps, a)
}
}
if f.Arg2 == nil {
if f.Left {
ps.startScope('(')
ps.writeString("...")
printOp()
foldParenthesize(f.Arg1)
ps.endScope(')')
} else {
ps.startScope('(')
foldParenthesize(f.Arg1)
printOp()
ps.writeString("...")
ps.endScope(')')
}
} else {
ps.startScope('(')
foldParenthesize(f.Arg1)
printOp()
ps.writeString("...")
printOp()
foldParenthesize(f.Arg2)
ps.endScope(')')
}
}
func (f *Fold) Traverse(fn func(AST) bool) {
if fn(f) {
f.Op.Traverse(fn)
f.Arg1.Traverse(fn)
if f.Arg2 != nil {
f.Arg2.Traverse(fn)
}
}
}
func (f *Fold) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(f) {
return nil
}
op := f.Op.Copy(fn, skip)
arg1 := f.Arg1.Copy(fn, skip)
var arg2 AST
if f.Arg2 != nil {
arg2 = f.Arg2.Copy(fn, skip)
}
if op == nil && arg1 == nil && arg2 == nil {
return fn(f)
}
if op == nil {
op = f.Op
}
if arg1 == nil {
arg1 = f.Arg1
}
if arg2 == nil {
arg2 = f.Arg2
}
f = &Fold{Left: f.Left, Op: op, Arg1: arg1, Arg2: arg2}
if r := fn(f); r != nil {
return r
}
return f
}
func (f *Fold) GoString() string {
return f.goString(0, "")
}
func (f *Fold) goString(indent int, field string) string {
if f.Arg2 == nil {
return fmt.Sprintf("%*s%sFold: Left: %t\n%s\n%s", indent, "", field,
f.Left, f.Op.goString(indent+2, "Op: "),
f.Arg1.goString(indent+2, "Arg1: "))
} else {
return fmt.Sprintf("%*s%sFold: Left: %t\n%s\n%s\n%s", indent, "", field,
f.Left, f.Op.goString(indent+2, "Op: "),
f.Arg1.goString(indent+2, "Arg1: "),
f.Arg2.goString(indent+2, "Arg2: "))
}
}
// Subobject is a a reference to an offset in an expression. This is
// used for C++20 manglings of class types used as the type of
// non-type template arguments.
//
// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
type Subobject struct {
Type AST
SubExpr AST
Offset int
Selectors []int
PastEnd bool
}
func (so *Subobject) print(ps *printState) {
ps.print(so.SubExpr)
ps.writeString(".<")
ps.print(so.Type)
ps.writeString(fmt.Sprintf(" at offset %d>", so.Offset))
}
func (so *Subobject) Traverse(fn func(AST) bool) {
if fn(so) {
so.Type.Traverse(fn)
so.SubExpr.Traverse(fn)
}
}
func (so *Subobject) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(so) {
return nil
}
typ := so.Type.Copy(fn, skip)
subExpr := so.SubExpr.Copy(fn, skip)
if typ == nil && subExpr == nil {
return nil
}
if typ == nil {
typ = so.Type
}
if subExpr == nil {
subExpr = so.SubExpr
}
so = &Subobject{
Type: typ,
SubExpr: subExpr,
Offset: so.Offset,
Selectors: so.Selectors,
PastEnd: so.PastEnd,
}
if r := fn(so); r != nil {
return r
}
return so
}
func (so *Subobject) GoString() string {
return so.goString(0, "")
}
func (so *Subobject) goString(indent int, field string) string {
var selectors string
for _, s := range so.Selectors {
selectors += fmt.Sprintf(" %d", s)
}
return fmt.Sprintf("%*s%sSubobject:\n%s\n%s\n%*sOffset: %d\n%*sSelectors:%s\n%*sPastEnd: %t",
indent, "", field,
so.Type.goString(indent+2, "Type: "),
so.SubExpr.goString(indent+2, "SubExpr: "),
indent+2, "", so.Offset,
indent+2, "", selectors,
indent+2, "", so.PastEnd)
}
// PtrMemCast is a conversion of an expression to a pointer-to-member
// type. This is used for C++20 manglings of class types used as the
// type of non-type template arguments.
//
// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
type PtrMemCast struct {
Type AST
Expr AST
Offset int
}
func (pmc *PtrMemCast) print(ps *printState) {
ps.startScope('(')
ps.print(pmc.Type)
ps.writeString(")(")
ps.print(pmc.Expr)
ps.endScope(')')
}
func (pmc *PtrMemCast) Traverse(fn func(AST) bool) {
if fn(pmc) {
pmc.Type.Traverse(fn)
pmc.Expr.Traverse(fn)
}
}
func (pmc *PtrMemCast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(pmc) {
return nil
}
typ := pmc.Type.Copy(fn, skip)
expr := pmc.Expr.Copy(fn, skip)
if typ == nil && expr == nil {
return nil
}
if typ == nil {
typ = pmc.Type
}
if expr == nil {
expr = pmc.Expr
}
pmc = &PtrMemCast{
Type: typ,
Expr: expr,
Offset: pmc.Offset,
}
if r := fn(pmc); r != nil {
return r
}
return pmc
}
func (pmc *PtrMemCast) GoString() string {
return pmc.goString(0, "")
}
func (pmc *PtrMemCast) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sPtrMemCast:\n%s\n%s\n%*sOffset: %d",
indent, "", field,
pmc.Type.goString(indent+2, "Type: "),
pmc.Expr.goString(indent+2, "Expr: "),
indent+2, "", pmc.Offset)
}
// New is a use of operator new in an expression.
type New struct {
Op AST
Place AST
Type AST
Init AST
}
func (n *New) print(ps *printState) {
if !ps.llvmStyle {
// Op doesn't really matter for printing--we always print "new".
ps.writeString("new ")
} else {
op, _ := n.Op.(*Operator)
if op != nil {
ps.writeString(op.Name)
if n.Place == nil {
ps.writeByte(' ')
}
} else {
ps.print(n.Op)
}
}
if n.Place != nil {
parenthesize(ps, n.Place)
ps.writeByte(' ')
}
ps.print(n.Type)
if n.Init != nil {
parenthesize(ps, n.Init)
}
}
func (n *New) Traverse(fn func(AST) bool) {
if fn(n) {
n.Op.Traverse(fn)
if n.Place != nil {
n.Place.Traverse(fn)
}
n.Type.Traverse(fn)
if n.Init != nil {
n.Init.Traverse(fn)
}
}
}
func (n *New) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(n) {
return nil
}
op := n.Op.Copy(fn, skip)
var place AST
if n.Place != nil {
place = n.Place.Copy(fn, skip)
}
typ := n.Type.Copy(fn, skip)
var ini AST
if n.Init != nil {
ini = n.Init.Copy(fn, skip)
}
if op == nil && place == nil && typ == nil && ini == nil {
return fn(n)
}
if op == nil {
op = n.Op
}
if place == nil {
place = n.Place
}
if typ == nil {
typ = n.Type
}
if ini == nil {
ini = n.Init
}
n = &New{Op: op, Place: place, Type: typ, Init: ini}
if r := fn(n); r != nil {
return r
}
return n
}
func (n *New) GoString() string {
return n.goString(0, "")
}
func (n *New) goString(indent int, field string) string {
var place string
if n.Place == nil {
place = fmt.Sprintf("%*sPlace: nil", indent, "")
} else {
place = n.Place.goString(indent+2, "Place: ")
}
var ini string
if n.Init == nil {
ini = fmt.Sprintf("%*sInit: nil", indent, "")
} else {
ini = n.Init.goString(indent+2, "Init: ")
}
return fmt.Sprintf("%*s%sNew:\n%s\n%s\n%s\n%s", indent, "", field,
n.Op.goString(indent+2, "Op: "), place,
n.Type.goString(indent+2, "Type: "), ini)
}
// Literal is a literal in an expression.
type Literal struct {
Type AST
Val string
Neg bool
}
// Suffixes to use for constants of the given integer type.
var builtinTypeSuffix = map[string]string{
"int": "",
"unsigned int": "u",
"long": "l",
"unsigned long": "ul",
"long long": "ll",
"unsigned long long": "ull",
}
// Builtin float types.
var builtinTypeFloat = map[string]bool{
"double": true,
"long double": true,
"float": true,
"__float128": true,
"half": true,
}
func (l *Literal) print(ps *printState) {
isFloat := false
if b, ok := l.Type.(*BuiltinType); ok {
if suffix, ok := builtinTypeSuffix[b.Name]; ok {
if l.Neg {
ps.writeByte('-')
}
ps.writeString(l.Val)
ps.writeString(suffix)
return
} else if b.Name == "bool" && !l.Neg {
switch l.Val {
case "0":
ps.writeString("false")
return
case "1":
ps.writeString("true")
return
}
} else if b.Name == "decltype(nullptr)" && (l.Val == "" || l.Val == "0") {
if ps.llvmStyle {
ps.writeString("nullptr")
} else {
ps.print(l.Type)
}
return
} else {
isFloat = builtinTypeFloat[b.Name]
}
}
ps.startScope('(')
ps.print(l.Type)
ps.endScope(')')
if isFloat {
ps.writeByte('[')
}
if l.Neg {
ps.writeByte('-')
}
ps.writeString(l.Val)
if isFloat {
ps.writeByte(']')
}
}
func (l *Literal) Traverse(fn func(AST) bool) {
if fn(l) {
l.Type.Traverse(fn)
}
}
func (l *Literal) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(l) {
return nil
}
typ := l.Type.Copy(fn, skip)
if typ == nil {
return fn(l)
}
l = &Literal{Type: typ, Val: l.Val, Neg: l.Neg}
if r := fn(l); r != nil {
return r
}
return l
}
func (l *Literal) GoString() string {
return l.goString(0, "")
}
func (l *Literal) goString(indent int, field string) string {
var neg string
if l.Neg {
neg = " Neg: true"
}
return fmt.Sprintf("%*s%sLiteral:%s\n%s\n%*sVal: %s", indent, "", field,
neg, l.Type.goString(indent+2, "Type: "),
indent+2, "", l.Val)
}
func (l *Literal) prec() precedence {
return precPrimary
}
// StringLiteral is a string literal.
type StringLiteral struct {
Type AST
}
func (sl *StringLiteral) print(ps *printState) {
ps.writeString(`"<`)
sl.Type.print(ps)
ps.writeString(`>"`)
}
func (sl *StringLiteral) Traverse(fn func(AST) bool) {
if fn(sl) {
sl.Type.Traverse(fn)
}
}
func (sl *StringLiteral) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(sl) {
return nil
}
typ := sl.Type.Copy(fn, skip)
if typ == nil {
return fn(sl)
}
sl = &StringLiteral{Type: typ}
if r := fn(sl); r != nil {
return r
}
return sl
}
func (sl *StringLiteral) GoString() string {
return sl.goString(0, "")
}
func (sl *StringLiteral) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sStringLiteral:\n%s", indent, "", field,
sl.Type.goString(indent+2, ""))
}
// LambdaExpr is a literal that is a lambda expression.
type LambdaExpr struct {
Type AST
}
func (le *LambdaExpr) print(ps *printState) {
ps.writeString("[]")
if cl, ok := le.Type.(*Closure); ok {
cl.printTypes(ps)
}
ps.writeString("{...}")
}
func (le *LambdaExpr) Traverse(fn func(AST) bool) {
if fn(le) {
le.Type.Traverse(fn)
}
}
func (le *LambdaExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(le) {
return nil
}
typ := le.Type.Copy(fn, skip)
if typ == nil {
return fn(le)
}
le = &LambdaExpr{Type: typ}
if r := fn(le); r != nil {
return r
}
return le
}
func (le *LambdaExpr) GoString() string {
return le.goString(0, "")
}
func (le *LambdaExpr) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sLambdaExpr:\n%s", indent, "", field,
le.Type.goString(indent+2, ""))
}
// ExprList is a list of expressions, typically arguments to a
// function call in an expression.
type ExprList struct {
Exprs []AST
}
func (el *ExprList) print(ps *printState) {
ps.printList(el.Exprs, nil)
}
func (el *ExprList) Traverse(fn func(AST) bool) {
if fn(el) {
for _, e := range el.Exprs {
e.Traverse(fn)
}
}
}
func (el *ExprList) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(el) {
return nil
}
exprs := make([]AST, len(el.Exprs))
changed := false
for i, e := range el.Exprs {
ec := e.Copy(fn, skip)
if ec == nil {
exprs[i] = e
} else {
exprs[i] = ec
changed = true
}
}
if !changed {
return fn(el)
}
el = &ExprList{Exprs: exprs}
if r := fn(el); r != nil {
return r
}
return el
}
func (el *ExprList) GoString() string {
return el.goString(0, "")
}
func (el *ExprList) goString(indent int, field string) string {
if len(el.Exprs) == 0 {
return fmt.Sprintf("%*s%sExprList: nil", indent, "", field)
}
s := fmt.Sprintf("%*s%sExprList:", indent, "", field)
for i, e := range el.Exprs {
s += "\n"
s += e.goString(indent+2, fmt.Sprintf("%d: ", i))
}
return s
}
func (el *ExprList) prec() precedence {
return precComma
}
// InitializerList is an initializer list: an optional type with a
// list of expressions.
type InitializerList struct {
Type AST
Exprs AST
}
func (il *InitializerList) print(ps *printState) {
if il.Type != nil {
if array, ok := il.Type.(*ArrayType); ok {
if builtin, ok := array.Element.(*BuiltinType); ok && builtin.Name == "char" {
if il.printAsString(ps) {
return
}
}
}
}
if il.Type != nil {
ps.print(il.Type)
}
ps.writeByte('{')
ps.print(il.Exprs)
ps.writeByte('}')
}
// printAsString tries to print a char array initializer as a string.
// It reports whether it succeeded.
func (il *InitializerList) printAsString(ps *printState) bool {
exprList, ok := il.Exprs.(*ExprList)
if !ok {
return false
}
var sb strings.Builder
sb.WriteByte('"')
inNumericEscape := false
for _, e := range exprList.Exprs {
lit, ok := e.(*Literal)
if !ok {
return false
}
if lit.Neg {
return false
}
val, err := strconv.Atoi(lit.Val)
if err != nil || val > 255 {
return false
}
// If we just added a numeric escape,
// make sure it doesn't get accidentally extended
// (numeric escapes here are C++ syntax, not Go syntax).
if inNumericEscape {
if (val >= '0' && val <= '9') ||
(val >= 'a' && val <= 'f') ||
(val >= 'A' && val <= 'F') {
sb.WriteString(`""`)
}
}
inNumericEscape = false
switch val {
case '\a':
sb.WriteString(`\a`)
case '\b':
sb.WriteString(`\b`)
case '\f':
sb.WriteString(`\f`)
case '\n':
sb.WriteString(`\n`)
case '\r':
sb.WriteString(`\r`)
case '\t':
sb.WriteString(`\t`)
case '\v':
sb.WriteString(`\v`)
case '"':
sb.WriteString(`\"`)
case '\\':
sb.WriteString(`\\`)
default:
if val < 32 || val == 127 {
const hex = "0123456789ABCDEF"
sb.WriteByte('\\')
if val > 7 {
sb.WriteByte('x')
}
if val >= 16 {
sb.WriteByte(hex[val>>4])
}
sb.WriteByte(hex[val&0xf])
inNumericEscape = true
break
}
sb.WriteByte(byte(val))
}
}
sb.WriteByte('"')
ps.writeString(sb.String())
return true
}
func (il *InitializerList) Traverse(fn func(AST) bool) {
if fn(il) {
if il.Type != nil {
il.Type.Traverse(fn)
}
il.Exprs.Traverse(fn)
}
}
func (il *InitializerList) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(il) {
return nil
}
var typ AST
if il.Type != nil {
typ = il.Type.Copy(fn, skip)
}
exprs := il.Exprs.Copy(fn, skip)
if typ == nil && exprs == nil {
return fn(il)
}
if typ == nil {
typ = il.Type
}
if exprs == nil {
exprs = il.Exprs
}
il = &InitializerList{Type: typ, Exprs: exprs}
if r := fn(il); r != nil {
return r
}
return il
}
func (il *InitializerList) GoString() string {
return il.goString(0, "")
}
func (il *InitializerList) goString(indent int, field string) string {
var t string
if il.Type == nil {
t = fmt.Sprintf("%*sType: nil", indent+2, "")
} else {
t = il.Type.goString(indent+2, "Type: ")
}
return fmt.Sprintf("%*s%sInitializerList:\n%s\n%s", indent, "", field,
t, il.Exprs.goString(indent+2, "Exprs: "))
}
// DefaultArg holds a default argument for a local name.
type DefaultArg struct {
Num int
Arg AST
}
func (da *DefaultArg) print(ps *printState) {
if !ps.llvmStyle {
fmt.Fprintf(&ps.buf, "{default arg#%d}::", da.Num+1)
}
ps.print(da.Arg)
}
func (da *DefaultArg) Traverse(fn func(AST) bool) {
if fn(da) {
da.Arg.Traverse(fn)
}
}
func (da *DefaultArg) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(da) {
return nil
}
arg := da.Arg.Copy(fn, skip)
if arg == nil {
return fn(da)
}
da = &DefaultArg{Num: da.Num, Arg: arg}
if r := fn(da); r != nil {
return r
}
return da
}
func (da *DefaultArg) GoString() string {
return da.goString(0, "")
}
func (da *DefaultArg) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sDefaultArg: Num: %d\n%s", indent, "", field, da.Num,
da.Arg.goString(indent+2, "Arg: "))
}
// Closure is a closure, or lambda expression.
type Closure struct {
TemplateArgs []AST
TemplateArgsConstraint AST
Types []AST
Num int
CallConstraint AST
}
func (cl *Closure) print(ps *printState) {
if ps.llvmStyle {
if cl.Num == 0 {
ps.writeString("'lambda'")
} else {
ps.writeString(fmt.Sprintf("'lambda%d'", cl.Num-1))
}
} else {
ps.writeString("{lambda")
}
cl.printTypes(ps)
if !ps.llvmStyle {
ps.writeString(fmt.Sprintf("#%d}", cl.Num+1))
}
}
func (cl *Closure) printTypes(ps *printState) {
if len(cl.TemplateArgs) > 0 {
scopes := ps.scopes
ps.scopes = 0
ps.writeString("<")
ps.printList(cl.TemplateArgs, nil)
ps.writeString(">")
ps.scopes = scopes
}
if cl.TemplateArgsConstraint != nil {
ps.writeString(" requires ")
ps.print(cl.TemplateArgsConstraint)
ps.writeByte(' ')
}
ps.startScope('(')
ps.printList(cl.Types, nil)
ps.endScope(')')
if cl.CallConstraint != nil {
ps.writeString(" requires ")
ps.print(cl.CallConstraint)
}
}
func (cl *Closure) Traverse(fn func(AST) bool) {
if fn(cl) {
for _, a := range cl.TemplateArgs {
a.Traverse(fn)
}
if cl.TemplateArgsConstraint != nil {
cl.TemplateArgsConstraint.Traverse(fn)
}
for _, t := range cl.Types {
t.Traverse(fn)
}
if cl.CallConstraint != nil {
cl.CallConstraint.Traverse(fn)
}
}
}
func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(cl) {
return nil
}
changed := false
args := make([]AST, len(cl.TemplateArgs))
for i, a := range cl.TemplateArgs {
ac := a.Copy(fn, skip)
if ac == nil {
args[i] = a
} else {
args[i] = ac
changed = true
}
}
var templateArgsConstraint AST
if cl.TemplateArgsConstraint != nil {
templateArgsConstraint = cl.TemplateArgsConstraint.Copy(fn, skip)
if templateArgsConstraint == nil {
templateArgsConstraint = cl.TemplateArgsConstraint
} else {
changed = true
}
}
types := make([]AST, len(cl.Types))
for i, t := range cl.Types {
tc := t.Copy(fn, skip)
if tc == nil {
types[i] = t
} else {
types[i] = tc
changed = true
}
}
var callConstraint AST
if cl.CallConstraint != nil {
callConstraint = cl.CallConstraint.Copy(fn, skip)
if callConstraint == nil {
callConstraint = cl.CallConstraint
} else {
changed = true
}
}
if !changed {
return fn(cl)
}
cl = &Closure{
TemplateArgs: args,
TemplateArgsConstraint: templateArgsConstraint,
Types: types,
Num: cl.Num,
CallConstraint: callConstraint,
}
if r := fn(cl); r != nil {
return r
}
return cl
}
func (cl *Closure) GoString() string {
return cl.goString(0, "")
}
func (cl *Closure) goString(indent int, field string) string {
var args strings.Builder
if len(cl.TemplateArgs) == 0 {
fmt.Fprintf(&args, "%*sTemplateArgs: nil", indent+2, "")
} else {
fmt.Fprintf(&args, "%*sTemplateArgs:", indent+2, "")
for i, a := range cl.TemplateArgs {
args.WriteByte('\n')
args.WriteString(a.goString(indent+4, fmt.Sprintf("%d: ", i)))
}
}
var templateArgsConstraint string
if cl.TemplateArgsConstraint != nil {
templateArgsConstraint = "\n" + cl.TemplateArgsConstraint.goString(indent+2, "TemplateArgsConstraint: ")
}
var types strings.Builder
if len(cl.Types) == 0 {
fmt.Fprintf(&types, "%*sTypes: nil", indent+2, "")
} else {
fmt.Fprintf(&types, "%*sTypes:", indent+2, "")
for i, t := range cl.Types {
types.WriteByte('\n')
types.WriteString(t.goString(indent+4, fmt.Sprintf("%d: ", i)))
}
}
var callConstraint string
if cl.CallConstraint != nil {
callConstraint = "\n" + cl.CallConstraint.goString(indent+2, "CallConstraint: ")
}
return fmt.Sprintf("%*s%sClosure: Num: %d\n%s\n%s%s%s", indent, "", field,
cl.Num, args.String(), templateArgsConstraint, types.String(),
callConstraint)
}
// StructuredBindings is a structured binding declaration.
type StructuredBindings struct {
Bindings []AST
}
func (sb *StructuredBindings) print(ps *printState) {
ps.writeString("[")
ps.printList(sb.Bindings, nil)
ps.writeString("]")
}
func (sb *StructuredBindings) Traverse(fn func(AST) bool) {
if fn(sb) {
for _, b := range sb.Bindings {
b.Traverse(fn)
}
}
}
func (sb *StructuredBindings) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(sb) {
return nil
}
changed := false
bindings := make([]AST, len(sb.Bindings))
for i, b := range sb.Bindings {
bc := b.Copy(fn, skip)
if bc == nil {
bindings[i] = b
} else {
bindings[i] = bc
changed = true
}
}
if !changed {
return fn(sb)
}
sb = &StructuredBindings{Bindings: bindings}
if r := fn(sb); r != nil {
return r
}
return sb
}
func (sb *StructuredBindings) GoString() string {
return sb.goString(0, "")
}
func (sb *StructuredBindings) goString(indent int, field string) string {
var strb strings.Builder
fmt.Fprintf(&strb, "%*s%sStructuredBinding:", indent, "", field)
for _, b := range sb.Bindings {
strb.WriteByte('\n')
strb.WriteString(b.goString(indent+2, ""))
}
return strb.String()
}
// UnnamedType is an unnamed type, that just has an index.
type UnnamedType struct {
Num int
}
func (ut *UnnamedType) print(ps *printState) {
if ps.llvmStyle {
if ut.Num == 0 {
ps.writeString("'unnamed'")
} else {
ps.writeString(fmt.Sprintf("'unnamed%d'", ut.Num-1))
}
} else {
ps.writeString(fmt.Sprintf("{unnamed type#%d}", ut.Num+1))
}
}
func (ut *UnnamedType) Traverse(fn func(AST) bool) {
fn(ut)
}
func (ut *UnnamedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(ut) {
return nil
}
return fn(ut)
}
func (ut *UnnamedType) GoString() string {
return ut.goString(0, "")
}
func (ut *UnnamedType) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sUnnamedType: Num: %d", indent, "", field, ut.Num)
}
// UnnamedEnum is an unnamed enum type.
type UnnamedEnum struct {
Underlying AST
Name AST
}
func (ue *UnnamedEnum) print(ps *printState) {
ps.writeString("{enum:")
ps.print(ue.Underlying)
ps.writeByte('{')
ps.print(ue.Name)
ps.writeString("}}")
}
func (ue *UnnamedEnum) Traverse(fn func(AST) bool) {
if fn(ue) {
ue.Underlying.Traverse(fn)
ue.Name.Traverse(fn)
}
}
func (ue *UnnamedEnum) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(ue) {
return nil
}
underlying := ue.Underlying.Copy(fn, skip)
name := ue.Name.Copy(fn, skip)
if underlying == nil && name == nil {
return fn(ue)
}
if underlying == nil {
underlying = ue.Underlying
}
if name == nil {
name = ue.Name
}
ue = &UnnamedEnum{Underlying: underlying, Name: name}
if r := fn(ue); r != nil {
return r
}
return ue
}
func (ue *UnnamedEnum) GoString() string {
return ue.goString(0, "")
}
func (ue *UnnamedEnum) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sUnnamedEnum:\n%s\n%s", indent, "", field,
ue.Underlying.goString(indent+2, "Underlying: "),
ue.Name.goString(indent+2, "Name: "))
}
// Clone is a clone of a function, with a distinguishing suffix.
type Clone struct {
Base AST
Suffix string
}
func (c *Clone) print(ps *printState) {
ps.print(c.Base)
if ps.llvmStyle {
ps.writeByte(' ')
ps.startScope('(')
ps.writeString(c.Suffix)
ps.endScope(')')
} else {
ps.writeString(fmt.Sprintf(" [clone %s]", c.Suffix))
}
}
func (c *Clone) Traverse(fn func(AST) bool) {
if fn(c) {
c.Base.Traverse(fn)
}
}
func (c *Clone) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(c) {
return nil
}
base := c.Base.Copy(fn, skip)
if base == nil {
return fn(c)
}
c = &Clone{Base: base, Suffix: c.Suffix}
if r := fn(c); r != nil {
return r
}
return c
}
func (c *Clone) GoString() string {
return c.goString(0, "")
}
func (c *Clone) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sClone: Suffix: %s\n%s", indent, "", field,
c.Suffix, c.Base.goString(indent+2, "Base: "))
}
// Special is a special symbol, printed as a prefix plus another
// value.
type Special struct {
Prefix string
Val AST
}
func (s *Special) print(ps *printState) {
prefix := s.Prefix
if ps.llvmStyle {
switch prefix {
case "TLS wrapper function for ":
prefix = "thread-local wrapper routine for "
case "TLS init function for ":
prefix = "thread-local initialization routine for "
}
}
ps.writeString(prefix)
ps.print(s.Val)
}
func (s *Special) Traverse(fn func(AST) bool) {
if fn(s) {
s.Val.Traverse(fn)
}
}
func (s *Special) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(s) {
return nil
}
val := s.Val.Copy(fn, skip)
if val == nil {
return fn(s)
}
s = &Special{Prefix: s.Prefix, Val: val}
if r := fn(s); r != nil {
return r
}
return s
}
func (s *Special) GoString() string {
return s.goString(0, "")
}
func (s *Special) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sSpecial: Prefix: %s\n%s", indent, "", field,
s.Prefix, s.Val.goString(indent+2, "Val: "))
}
// Special2 is like special, but uses two values.
type Special2 struct {
Prefix string
Val1 AST
Middle string
Val2 AST
}
func (s *Special2) print(ps *printState) {
ps.writeString(s.Prefix)
ps.print(s.Val1)
ps.writeString(s.Middle)
ps.print(s.Val2)
}
func (s *Special2) Traverse(fn func(AST) bool) {
if fn(s) {
s.Val1.Traverse(fn)
s.Val2.Traverse(fn)
}
}
func (s *Special2) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(s) {
return nil
}
val1 := s.Val1.Copy(fn, skip)
val2 := s.Val2.Copy(fn, skip)
if val1 == nil && val2 == nil {
return fn(s)
}
if val1 == nil {
val1 = s.Val1
}
if val2 == nil {
val2 = s.Val2
}
s = &Special2{Prefix: s.Prefix, Val1: val1, Middle: s.Middle, Val2: val2}
if r := fn(s); r != nil {
return r
}
return s
}
func (s *Special2) GoString() string {
return s.goString(0, "")
}
func (s *Special2) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sSpecial2: Prefix: %s\n%s\n%*sMiddle: %s\n%s", indent, "", field,
s.Prefix, s.Val1.goString(indent+2, "Val1: "),
indent+2, "", s.Middle, s.Val2.goString(indent+2, "Val2: "))
}
// EnableIf is used by clang for an enable_if attribute.
type EnableIf struct {
Type AST
Args []AST
}
func (ei *EnableIf) print(ps *printState) {
ps.print(ei.Type)
ps.writeString(" [enable_if:")
ps.printList(ei.Args, nil)
ps.writeString("]")
}
func (ei *EnableIf) Traverse(fn func(AST) bool) {
if fn(ei) {
ei.Type.Traverse(fn)
for _, a := range ei.Args {
a.Traverse(fn)
}
}
}
func (ei *EnableIf) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(ei) {
return nil
}
typ := ei.Type.Copy(fn, skip)
argsChanged := false
args := make([]AST, len(ei.Args))
for i, a := range ei.Args {
ac := a.Copy(fn, skip)
if ac == nil {
args[i] = a
} else {
args[i] = ac
argsChanged = true
}
}
if typ == nil && !argsChanged {
return fn(ei)
}
if typ == nil {
typ = ei.Type
}
ei = &EnableIf{Type: typ, Args: args}
if r := fn(ei); r != nil {
return r
}
return ei
}
func (ei *EnableIf) GoString() string {
return ei.goString(0, "")
}
func (ei *EnableIf) goString(indent int, field string) string {
var args string
if len(ei.Args) == 0 {
args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
} else {
args = fmt.Sprintf("%*sArgs:", indent+2, "")
for i, a := range ei.Args {
args += "\n"
args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
}
}
return fmt.Sprintf("%*s%sEnableIf:\n%s\n%s", indent, "", field,
ei.Type.goString(indent+2, "Type: "), args)
}
// ModuleName is a C++20 module.
type ModuleName struct {
Parent AST
Name AST
IsPartition bool
}
func (mn *ModuleName) print(ps *printState) {
if mn.Parent != nil {
ps.print(mn.Parent)
}
if mn.IsPartition {
ps.writeByte(':')
} else if mn.Parent != nil {
ps.writeByte('.')
}
ps.print(mn.Name)
}
func (mn *ModuleName) Traverse(fn func(AST) bool) {
if fn(mn) {
if mn.Parent != nil {
mn.Parent.Traverse(fn)
}
mn.Name.Traverse(fn)
}
}
func (mn *ModuleName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(mn) {
return nil
}
var parent AST
if mn.Parent != nil {
parent = mn.Parent.Copy(fn, skip)
}
name := mn.Name.Copy(fn, skip)
if parent == nil && name == nil {
return fn(mn)
}
if parent == nil {
parent = mn.Parent
}
if name == nil {
name = mn.Name
}
mn = &ModuleName{Parent: parent, Name: name, IsPartition: mn.IsPartition}
if r := fn(mn); r != nil {
return r
}
return mn
}
func (mn *ModuleName) GoString() string {
return mn.goString(0, "")
}
func (mn *ModuleName) goString(indent int, field string) string {
var parent string
if mn.Parent == nil {
parent = fmt.Sprintf("%*sParent: nil", indent+2, "")
} else {
parent = mn.Parent.goString(indent+2, "Parent: ")
}
return fmt.Sprintf("%*s%sModuleName: IsPartition: %t\n%s\n%s", indent, "", field,
mn.IsPartition, parent,
mn.Name.goString(indent+2, "Name: "))
}
// ModuleEntity is a name inside a module.
type ModuleEntity struct {
Module AST
Name AST
}
func (me *ModuleEntity) print(ps *printState) {
ps.print(me.Name)
ps.writeByte('@')
ps.print(me.Module)
}
func (me *ModuleEntity) Traverse(fn func(AST) bool) {
if fn(me) {
me.Module.Traverse(fn)
me.Name.Traverse(fn)
}
}
func (me *ModuleEntity) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(me) {
return nil
}
module := me.Module.Copy(fn, skip)
name := me.Name.Copy(fn, skip)
if module == nil && name == nil {
return fn(me)
}
if module == nil {
module = me.Module
}
if name == nil {
name = me.Name
}
me = &ModuleEntity{Module: module, Name: name}
if r := fn(me); r != nil {
return r
}
return me
}
func (me *ModuleEntity) GoString() string {
return me.goString(0, "")
}
func (me *ModuleEntity) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sModuleEntity:\n%s\n%s", indent, "", field,
me.Module.goString(indent+2, "Module: "),
me.Name.goString(indent+2, "Name: "))
}
// Friend is a member like friend name.
type Friend struct {
Name AST
}
func (f *Friend) print(ps *printState) {
if ps.llvmStyle {
ps.writeString("friend ")
}
ps.print(f.Name)
if !ps.llvmStyle {
ps.writeString("[friend]")
}
}
func (f *Friend) Traverse(fn func(AST) bool) {
if fn(f) {
f.Name.Traverse(fn)
}
}
func (f *Friend) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(f) {
return nil
}
name := f.Name.Copy(fn, skip)
if name == nil {
return fn(f)
}
f = &Friend{Name: name}
if r := fn(f); r != nil {
return r
}
return f
}
func (f *Friend) GoString() string {
return f.goString(0, "")
}
func (f *Friend) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sFriend:\n%s", indent, "", field,
f.Name.goString(indent+2, "Name: "))
}
// Constraint represents an AST with a constraint.
// ForTemplateArgs is true if this constraint was found at the
// end of a list of template arguments. We need that because
// in LLVM style we don't print constraints of that sort.
type Constraint struct {
Name AST
Requires AST
ForTemplateArgs bool
}
func (c *Constraint) print(ps *printState) {
ps.print(c.Name)
// For LLVM style skip the constraint on a template.
if ps.llvmStyle && c.ForTemplateArgs {
return
}
ps.writeString(" requires ")
ps.print(c.Requires)
}
func (c *Constraint) Traverse(fn func(AST) bool) {
if fn(c) {
c.Name.Traverse(fn)
c.Requires.Traverse(fn)
}
}
func (c *Constraint) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(c) {
return nil
}
name := c.Name.Copy(fn, skip)
requires := c.Requires.Copy(fn, skip)
if name == nil && requires == nil {
return fn(c)
}
if name == nil {
name = c.Name
}
if requires == nil {
requires = c.Requires
}
c = &Constraint{
Name: name,
Requires: requires,
ForTemplateArgs: c.ForTemplateArgs,
}
if r := fn(c); r != nil {
return r
}
return c
}
func (c *Constraint) GoString() string {
return c.goString(0, "")
}
func (c *Constraint) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sConstraint: ForTemplateArgs: %t\n%s\n%s", indent, "", field,
c.ForTemplateArgs,
c.Name.goString(indent+2, "Name: "),
c.Requires.goString(indent+2, "Requires: "))
}
// RequiresExpr is a C++20 requires expression.
type RequiresExpr struct {
Params []AST
Requirements []AST
}
func (re *RequiresExpr) print(ps *printState) {
ps.writeString("requires")
if len(re.Params) > 0 {
ps.writeByte(' ')
ps.startScope('(')
ps.printList(re.Params, nil)
ps.endScope(')')
}
ps.writeByte(' ')
ps.startScope('{')
for _, req := range re.Requirements {
ps.print(req)
}
ps.writeByte(' ')
ps.endScope('}')
}
func (re *RequiresExpr) Traverse(fn func(AST) bool) {
if fn(re) {
for _, p := range re.Params {
p.Traverse(fn)
}
for _, r := range re.Requirements {
r.Traverse(fn)
}
}
}
func (re *RequiresExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(re) {
return nil
}
changed := false
var params []AST
if len(re.Params) > 0 {
params = make([]AST, len(re.Params))
for i, p := range re.Params {
pc := p.Copy(fn, skip)
if pc == nil {
params[i] = p
} else {
params[i] = pc
changed = true
}
}
}
requirements := make([]AST, len(re.Requirements))
for i, r := range re.Requirements {
rc := r.Copy(fn, skip)
if rc == nil {
requirements[i] = r
} else {
requirements[i] = rc
changed = true
}
}
if !changed {
return fn(re)
}
re = &RequiresExpr{Params: params, Requirements: requirements}
if r := fn(re); r != nil {
return r
}
return re
}
func (re *RequiresExpr) GoString() string {
return re.goString(0, "")
}
func (re *RequiresExpr) goString(indent int, field string) string {
var params strings.Builder
if len(re.Params) == 0 {
fmt.Fprintf(¶ms, "%*sParams: nil", indent+2, "")
} else {
fmt.Fprintf(¶ms, "%*sParams:", indent+2, "")
for i, p := range re.Params {
params.WriteByte('\n')
params.WriteString(p.goString(indent+4, fmt.Sprintf("%d: ", i)))
}
}
var requirements strings.Builder
fmt.Fprintf(&requirements, "%*sRequirements:", indent+2, "")
for i, r := range re.Requirements {
requirements.WriteByte('\n')
requirements.WriteString(r.goString(indent+4, fmt.Sprintf("%d: ", i)))
}
return fmt.Sprintf("%*s%sRequirements:\n%s\n%s", indent, "", field,
params.String(), requirements.String())
}
// ExprRequirement is a simple requirement in a requires expression.
// This is an arbitrary expression.
type ExprRequirement struct {
Expr AST
Noexcept bool
TypeReq AST
}
func (er *ExprRequirement) print(ps *printState) {
ps.writeByte(' ')
if er.Noexcept || er.TypeReq != nil {
ps.startScope('{')
}
ps.print(er.Expr)
if er.Noexcept || er.TypeReq != nil {
ps.endScope('}')
}
if er.Noexcept {
ps.writeString(" noexcept")
}
if er.TypeReq != nil {
ps.writeString(" -> ")
ps.print(er.TypeReq)
}
ps.writeByte(';')
}
func (er *ExprRequirement) Traverse(fn func(AST) bool) {
if fn(er) {
er.Expr.Traverse(fn)
if er.TypeReq != nil {
er.TypeReq.Traverse(fn)
}
}
}
func (er *ExprRequirement) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(er) {
return nil
}
expr := er.Expr.Copy(fn, skip)
var typeReq AST
if er.TypeReq != nil {
typeReq = er.TypeReq.Copy(fn, skip)
}
if expr == nil && typeReq == nil {
return fn(er)
}
if expr == nil {
expr = er.Expr
}
if typeReq == nil {
typeReq = er.TypeReq
}
er = &ExprRequirement{Expr: expr, TypeReq: typeReq}
if r := fn(er); r != nil {
return r
}
return er
}
func (er *ExprRequirement) GoString() string {
return er.goString(0, "")
}
func (er *ExprRequirement) goString(indent int, field string) string {
var typeReq string
if er.TypeReq != nil {
typeReq = "\n" + er.TypeReq.goString(indent+2, "TypeReq: ")
}
return fmt.Sprintf("%*s%sExprRequirement: Noexcept: %t\n%s%s", indent, "", field,
er.Noexcept,
er.Expr.goString(indent+2, "Expr: "),
typeReq)
}
// TypeRequirement is a type requirement in a requires expression.
type TypeRequirement struct {
Type AST
}
func (tr *TypeRequirement) print(ps *printState) {
ps.writeString(" typename ")
ps.print(tr.Type)
ps.writeByte(';')
}
func (tr *TypeRequirement) Traverse(fn func(AST) bool) {
if fn(tr) {
tr.Type.Traverse(fn)
}
}
func (tr *TypeRequirement) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(tr) {
return nil
}
typ := tr.Type.Copy(fn, skip)
if typ == nil {
return fn(tr)
}
tr = &TypeRequirement{Type: typ}
if r := fn(tr); r != nil {
return r
}
return tr
}
func (tr *TypeRequirement) GoString() string {
return tr.goString(0, "")
}
func (tr *TypeRequirement) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sTypeRequirement:\n%s", indent, "", field,
tr.Type.goString(indent+2, ""))
}
// NestedRequirement is a nested requirement in a requires expression.
type NestedRequirement struct {
Constraint AST
}
func (nr *NestedRequirement) print(ps *printState) {
ps.writeString(" requires ")
ps.print(nr.Constraint)
ps.writeByte(';')
}
func (nr *NestedRequirement) Traverse(fn func(AST) bool) {
if fn(nr) {
nr.Constraint.Traverse(fn)
}
}
func (nr *NestedRequirement) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(nr) {
return nil
}
constraint := nr.Constraint.Copy(fn, skip)
if constraint == nil {
return fn(nr)
}
nr = &NestedRequirement{Constraint: constraint}
if r := fn(nr); r != nil {
return r
}
return nr
}
func (nr *NestedRequirement) GoString() string {
return nr.goString(0, "")
}
func (nr *NestedRequirement) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sNestedRequirement:\n%s", indent, "", field,
nr.Constraint.goString(indent+2, ""))
}
// ExplicitObjectParameter represents a C++23 explicit object parameter.
type ExplicitObjectParameter struct {
Base AST
}
func (eop *ExplicitObjectParameter) print(ps *printState) {
ps.writeString("this ")
ps.print(eop.Base)
}
func (eop *ExplicitObjectParameter) Traverse(fn func(AST) bool) {
if fn(eop) {
eop.Base.Traverse(fn)
}
}
func (eop *ExplicitObjectParameter) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(eop) {
return nil
}
base := eop.Base.Copy(fn, skip)
if base == nil {
return fn(eop)
}
eop = &ExplicitObjectParameter{Base: base}
if r := fn(eop); r != nil {
return r
}
return eop
}
func (eop *ExplicitObjectParameter) GoString() string {
return eop.goString(0, "")
}
func (eop *ExplicitObjectParameter) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sExplicitObjectParameter:\n%s", indent, "", field,
eop.Base.goString(indent+2, ""))
}
// Print the inner types.
func (ps *printState) printInner(prefixOnly bool) []AST {
var save []AST
var psave *[]AST
if prefixOnly {
psave = &save
}
for len(ps.inner) > 0 {
ps.printOneInner(psave)
}
return save
}
// innerPrinter is an interface for types that can print themselves as
// inner types.
type innerPrinter interface {
printInner(*printState)
}
// Print the most recent inner type. If save is not nil, only print
// prefixes.
func (ps *printState) printOneInner(save *[]AST) {
if len(ps.inner) == 0 {
panic("printOneInner called with no inner types")
}
ln := len(ps.inner)
a := ps.inner[ln-1]
ps.inner = ps.inner[:ln-1]
if save != nil {
if _, ok := a.(*MethodWithQualifiers); ok {
*save = append(*save, a)
return
}
}
if ip, ok := a.(innerPrinter); ok {
ip.printInner(ps)
} else {
ps.print(a)
}
}
// isEmpty returns whether printing a will not print anything.
func (ps *printState) isEmpty(a AST) bool {
switch a := a.(type) {
case *ArgumentPack:
for _, a := range a.Args {
if !ps.isEmpty(a) {
return false
}
}
return true
case *ExprList:
return len(a.Exprs) == 0
case *PackExpansion:
return a.Pack != nil && ps.isEmpty(a.Base)
default:
return false
}
}
================================================
FILE: ast_test.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package demangle
import (
"fmt"
"testing"
)
func TestASTToString(t *testing.T) {
var tests = []struct {
input AST
want string
formatted string
}{
{
&Qualified{Scope: &Name{Name: "s"}, Name: &Name{Name: "C"}},
"s::C",
`Qualified:
Scope: s
Name: C`,
},
{
&Typed{Name: &Name{Name: "v"}, Type: &BuiltinType{"int"}},
"int v",
`Typed:
Name: v
Type: BuiltinType: int`,
},
}
for i, test := range tests {
if got := ASTToString(test.input); got != test.want {
t.Errorf("ASTToString of test %d == %s, want %s", i, test.input, test.want)
}
if got := fmt.Sprintf("%#v", test.input); got != test.formatted {
t.Errorf("Formatted test %d == %s, want %s", i, got, test.formatted)
}
}
}
================================================
FILE: c++filt.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
// +build ignore
// This is a program that works like the GNU c++filt program.
// It's here for testing purposes and as an example.
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
"strings"
"unicode"
"github.com/ianlancetaylor/demangle"
)
func flagUsage() {
usage(os.Stderr, 2)
}
func usage(w io.Writer, status int) {
fmt.Fprintf(w, "Usage: %s [options] [mangled names]\n", os.Args[0])
flag.CommandLine.SetOutput(w)
flag.PrintDefaults()
fmt.Fprintln(w, `Demangled names are displayed to stdout
If a name cannot be demangled it is just echoed to stdout.
If no names are provided on the command line, stdin is read.`)
os.Exit(status)
}
var stripUnderscore = flag.Bool("_", false, "Ignore first leading underscore")
var noParams = flag.Bool("p", false, "Do not display function argument types")
var noTemplateParams = flag.Bool("T", false, "Do not display template parameters")
var noEnclosingParams = flag.Bool("e", false, "Do not display enclosing parameters")
var noVerbose = flag.Bool("i", false, "Do not show implementation details (if any)")
var help = flag.Bool("h", false, "Display help information")
var debug = flag.Bool("d", false, "Display debugging information for strings on command line")
var llvm = flag.Bool("llvm", false, "Demangle strings in LLVM style")
var maxLen = flag.Int("m", 0, "Maximum length as power of 2, between 1 and 30")
// Unimplemented c++filt flags:
// -n (opposite of -_)
// -t (demangle types)
// -s (set demangling style)
// -V (print version information)
// Characters considered to be part of a symbol.
const symbolChars = "_$."
func main() {
flag.Usage = func() { usage(os.Stderr, 1) }
flag.Parse()
if *help {
usage(os.Stdout, 0)
}
out := bufio.NewWriter(os.Stdout)
if flag.NArg() > 0 {
for _, f := range flag.Args() {
if *debug {
a, err := demangle.ToAST(f, options()...)
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", f, err)
} else {
fmt.Fprintf(out, "%#v\n", a)
}
} else {
doDemangle(out, f)
}
out.WriteByte('\n')
}
if err := out.Flush(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
return
}
scanner := bufio.NewScanner(bufio.NewReader(os.Stdin))
scanner.Buffer(nil, 1<<30)
for scanner.Scan() {
line := scanner.Text()
start := -1
for i, c := range line {
if unicode.IsLetter(c) || unicode.IsNumber(c) || strings.ContainsRune(symbolChars, c) {
if start < 0 {
start = i
}
} else {
if start >= 0 {
doDemangle(out, line[start:i])
}
out.WriteRune(c)
start = -1
}
}
if start >= 0 {
doDemangle(out, line[start:])
start = -1
}
out.WriteByte('\n')
if err := out.Flush(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
}
// Demangle a string just as the GNU c++filt program does.
func doDemangle(out *bufio.Writer, name string) {
skip := 0
if name[0] == '.' || name[0] == '$' {
skip++
}
if *stripUnderscore && name[skip] == '_' {
skip++
}
result := demangle.Filter(name[skip:], options()...)
if result == name[skip:] {
out.WriteString(name)
} else {
if name[0] == '.' {
out.WriteByte('.')
}
out.WriteString(result)
}
}
// options returns the demangling options to use based on the command
// line flags.
func options() []demangle.Option {
var options []demangle.Option
if *noParams {
options = append(options, demangle.NoParams)
}
if *noTemplateParams {
options = append(options, demangle.NoTemplateParams)
}
if *noEnclosingParams {
options = append(options, demangle.NoEnclosingParams)
}
if !*noVerbose {
options = append(options, demangle.Verbose)
}
if *llvm {
options = append(options, demangle.LLVMStyle)
}
if *maxLen > 0 {
options = append(options, demangle.MaxLength(*maxLen))
}
return options
}
================================================
FILE: cases_test.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package demangle
import (
"bufio"
"io"
"os"
"strings"
"testing"
)
// casesExpectedFailures is a list of exceptions from cases that we
// don't expect to pass. This is to let us incrementally fix them
// over time.
var casesExpectedFailures = map[string]bool{
"_ZSteqIcEN9__gnu_cxx11__enable_ifIXsr9__is_charIT_EE7__valueEbE6__typeERKSbIS2_St11char_traitsIS2_ESaIS2_EESA_": true,
"_Z1fPU11objcproto1A11objc_object": true,
"_Z1fPKU11objcproto1A7NSArray": true,
"_ZNK1AIJ1Z1Y1XEEcv1BIJDpPT_EEIJS2_S1_S0_EEEv": true,
"_ZNK3Ncr6Silver7Utility6detail12CallOnThreadIZ53-[DeploymentSetupController handleManualServerEntry:]E3$_5EclIJEEEDTclclL_ZNS2_4getTIS4_EERT_vEEspclsr3stdE7forwardIT_Efp_EEEDpOSA_": true,
"_Z1fIJicEEvDp7MuncherIAstT__S1_E": true,
"_ZN5test31aINS_1XEMS1_PiEEvT_T0_DTdsfL0p_fL0p0_E": true,
"_Z1fPU3AS1KiS0_": true,
"_Z1pILb1EEiM1SKDOT_EFivRE": true,
"_Z1pIJicfEEiM1SVKDwDpT_EFivOE": true,
"_ZZ18test_assign_throwsI20small_throws_on_copyLb0EEvvENKUlRNSt3__13anyEOT_E_clIRS0_EEDaS3_S5_": true,
"_ZN1Scv7MuncherIJDpPT_EEIJFivEA_iEEEv": true,
"_Z2f8IiJ8identityIiES0_IfEEEvRAsPiDpT0_T_DpNS3_4typeEE_i": true,
"_ZZ11inline_funcvENKUlTyTyT_T0_E_clIiiEEDaS_S0_": true,
"_ZZ11inline_funcvENKUlTyTyT_T1_T0_E_clIiiiEEDaS_S0_S1_": true,
"_Z1fIXfLpm1x1yEEvv": true,
"_Z1fIXfLds1x1yEEvv": true,
}
// caseExceptions is a list of exceptions from the LLVM list that we
// do not handle the same as the LLVM demangler. We keep a list of
// exceptions so that we can use an exact copy of the test cases. We
// map to an empty string if we expect a demangling failure; this
// differs from caseExpectedFailures in that we've decided that we
// intentionally should not demangle this case. Otherwise this maps
// to the expected demangling.
var casesExceptions = map[string]string{
"_ZN1XIZ1fIiEvOT_EUlOT_DpT0_E_EclIJEEEvDpT_": "void X<void f<int>(int&&)::'lambda'(auto&&, auto)>::operator()<>()",
"_ZN1XIZ1fIiEvOT_EUlS2_DpT0_E_EclIJEEEvDpT_": "void X<void f<int>(int&&)::'lambda'(auto&&, auto)>::operator()<>()",
"_Z1h1XIJZ1fIiEDaOT_E1AZ1gIdEDaS2_E1BEE": "h(X<auto f<int>(int&&)::A, auto g<double>(double&&)::B>)",
"_Zcv1BIRT_EIS1_E": "",
// For the next four test cases it seems to me that
// <int, int>(int) is more correct than <int, int>(auto).
// It depends on how we handle a template parameter in
// and out of a lambda expression.
"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E_clIiiEEDaS3_Q1CIDtfp_EE": "auto void test7::f<int>()::'lambda'<typename $T> requires C<T> && C<TL0_> (auto)::operator()<int, int>(int) const requires C<decltype(fp)>",
"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E0_clIiiEEDaS3_Qaa1CIDtfp_EELb1E": "auto void test7::f<int>()::'lambda0'<typename $T> requires C<T> && C<TL0_> (auto)::operator()<int, int>(int) const requires C<decltype(fp)> && true",
"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E1_clIiiEEDaS3_Q1CIDtfp_EE": "auto void test7::f<int>()::'lambda1'<typename $T> requires C<T> && C<TL0_> (auto)::operator()<int, int>(int) const requires C<decltype(fp)>",
"_ZZN5test71fIiEEvvENKUlTyT0_E_clIiiEEDaS1_": "auto void test7::f<int>()::'lambda'<typename $T>(auto)::operator()<int, int>(int) const",
}
func TestCases(t *testing.T) {
t.Parallel()
cases := readCases(t)
expectedErrors := 0
expectedDifferent := 0
found := make(map[string]bool)
for _, test := range cases {
expectedFail := casesExpectedFailures[test[0]]
exception, haveException := casesExceptions[test[0]]
if expectedFail && haveException {
t.Errorf("test case error: %s in both expectedFailures and exceptions", test[0])
}
want := test[1]
if haveException && exception != "" {
if want == exception {
t.Errorf("test case error: %s exception is expected result", test[0])
}
want = exception
}
// We don't strip an extra underscore.
testStr := test[0]
if strings.HasPrefix(testStr, "__Z") || strings.HasPrefix(testStr, "____Z") {
testStr = testStr[1:]
}
// We don't demangle plain types, so just skip them.
if !strings.HasPrefix(testStr, "_") {
continue
}
if got, err := ToString(testStr, LLVMStyle); err != nil {
if expectedFail || (haveException && exception == "") {
t.Logf("demangling %s: expected failure: error %v", test[0], err)
if expectedFail {
expectedErrors++
found[test[0]] = true
}
} else {
t.Errorf("demangling %s: unexpected error %v", test[0], err)
}
} else if got != want {
if expectedFail {
t.Logf("demangling %s: expected failure: got %s, want %s", test[0], got, want)
expectedDifferent++
found[test[0]] = true
} else if haveException && exception == "" {
t.Errorf("demangling %s: expected to fail, but succeeded with %s", test[0], got)
} else {
t.Errorf("demangling %s: got %s, want %s", test[0], got, want)
}
} else if expectedFail || (haveException && exception == "") {
t.Errorf("demangling %s: expected to fail, but succeeded with %s", test[0], got)
if expectedFail {
found[test[0]] = true
}
}
}
if len(found) != len(casesExpectedFailures) {
for expected := range casesExpectedFailures {
if !found[expected] {
t.Errorf("expected %s to fail but did not see it", expected)
}
}
for f := range found {
if !casesExpectedFailures[f] {
t.Errorf("internal error: found failing but unexpected %s", f)
}
}
}
if expectedDifferent > 0 {
t.Logf("%d different demanglings out of %d cases", expectedDifferent, len(cases))
}
if expectedErrors > 0 {
t.Logf("%d expected failures out of %d cases", expectedErrors, len(cases))
}
}
// readCases reads the LLVM test cases from DemangleTestCases.inc.
// That file is copied from
//
// llvm-project/libcxxabi/test/DemangleTestCases.inc
//
// That file has no license, but LLVM in general has the license text:
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// This file is only used for testing and does not form part of the
// demangle package when it is used by other code.
//
// The file does not contain any code, only test cases and comments.
func readCases(t testing.TB) [][2]string {
const fn = "testdata/DemangleTestCases.inc"
f, err := os.Open(fn)
if err != nil {
t.Fatal(err)
}
defer f.Close()
var cases [][2]string
r := bufio.NewReader(f)
lineno := 1
for {
b, atEOF := readCasesUnquotedByte(t, r, fn, &lineno)
if atEOF {
break
}
if b != '{' {
t.Fatalf("%s:%d: got %c, want {", fn, lineno, b)
}
s1 := readCasesString(t, r, fn, &lineno)
for {
b = readCasesUnquotedByteNoEOF(t, r, fn, &lineno)
if b == ',' {
break
}
if b != '"' {
t.Fatalf("%s:%d: got %c, want ,", fn, lineno, b)
}
r.UnreadByte()
s1 += readCasesString(t, r, fn, &lineno)
}
s2 := readCasesString(t, r, fn, &lineno)
for {
b = readCasesUnquotedByteNoEOF(t, r, fn, &lineno)
if b == '}' {
break
}
if b != '"' {
t.Fatalf("%s:%d: got %c, want }", fn, lineno, b)
}
r.UnreadByte()
s2 += readCasesString(t, r, fn, &lineno)
}
b = readCasesUnquotedByteNoEOF(t, r, fn, &lineno)
if b != ',' {
t.Fatalf("%s:%d: got %c, want ,", fn, lineno, b)
}
cases = append(cases, [2]string{s1, s2})
}
return cases
}
// readCasesString reads a quoted string from the cases file.
func readCasesString(t testing.TB, r *bufio.Reader, fn string, lineno *int) string {
b, atEOF := readCasesUnquotedByte(t, r, fn, lineno)
if atEOF {
t.Fatalf(`%s:%d: got EOF, want "`, fn, *lineno)
}
if b != '"' {
t.Fatalf(`%s:%d: got %c, want "`, fn, *lineno, b)
}
var sb strings.Builder
for {
b = readCasesByteNoEOF(t, r, fn, *lineno)
if b == '"' {
break
}
if b != '\\' {
sb.WriteByte(b)
continue
}
b = readCasesByteNoEOF(t, r, fn, *lineno)
switch b {
case '"', '\'', '?', '\\':
sb.WriteByte(b)
continue
case 't':
sb.WriteByte('\t')
continue
case '0', '1', '2', '3', '4', '5', '6', '7':
val := b - '0'
octalLoop:
for {
b = readCasesByteNoEOF(t, r, fn, *lineno)
switch b {
case '0', '1', '2', '3', '4', '5', '6', '7':
val <<= 3
val += b - '0'
default:
r.UnreadByte()
break octalLoop
}
}
sb.WriteByte(val)
case 'x':
val := byte(0)
seen := false
hexLoop:
for {
b = readCasesByteNoEOF(t, r, fn, *lineno)
bval := byte(0)
switch b {
case '0', '1', '2', '3', '4', '5', '6', '7':
bval = b - '0'
case 'A', 'B', 'C', 'D', 'E', 'F':
bval = b - 'A'
case 'a', 'b', 'c', 'd', 'e', 'f':
bval = b - 'a'
default:
r.UnreadByte()
break hexLoop
}
val <<= 4
val += bval
seen = true
}
if !seen {
t.Fatalf(`%s:%d: no hex digits after \x`, fn, *lineno)
}
sb.WriteByte(val)
default:
t.Fatalf(`%s:%d: unexpected escape sequence \%c in string`, fn, *lineno, b)
}
}
return sb.String()
}
// readCasesUnquotedByte reads a byte from the cases file,
// where the byte is not in a quoted string.
// This skips comments and whitespace.
// The bool result reports whether we are at EOF.
func readCasesUnquotedByte(t testing.TB, r *bufio.Reader, fn string, lineno *int) (byte, bool) {
for {
b, atEOF := readCasesByte(t, r, fn, *lineno)
if atEOF {
return 0, true
}
if b == ' ' || b == '\t' {
continue
}
if b == '\n' {
*lineno++
continue
}
if b == '/' {
b, atEOF = readCasesByte(t, r, fn, *lineno)
if atEOF || b != '/' {
t.Fatalf("%s:%d: unexpected single /", fn, *lineno)
}
for {
_, err := r.ReadSlice('\n')
if err == nil {
*lineno++
break
}
switch err {
case bufio.ErrBufferFull:
case io.EOF:
return 0, true
default:
t.Fatalf("%s:%d: %v", fn, *lineno, err)
}
}
continue
}
return b, false
}
}
// readCasesUnquotedByteNoEOF is like readCasesUnquotedByte,
// but fails on EOF.
func readCasesUnquotedByteNoEOF(t testing.TB, r *bufio.Reader, fn string, lineno *int) byte {
b, atEOF := readCasesUnquotedByte(t, r, fn, lineno)
if atEOF {
t.Helper()
t.Fatalf("%s:%d: unexpected EOF", fn, *lineno)
}
return b
}
// readCasesByte reads a byte from the cases file.
// The bool result reports whether we are at EOF.
func readCasesByte(t testing.TB, r *bufio.Reader, fn string, lineno int) (byte, bool) {
b, err := r.ReadByte()
if err != nil {
if err == io.EOF {
return 0, true
}
t.Helper()
t.Fatalf("%s:%d: %v", fn, lineno, err)
}
return b, false
}
// readCasesByteNoEOF is like readCasesByte, but fails on EOF.
func readCasesByteNoEOF(t testing.TB, r *bufio.Reader, fn string, lineno int) byte {
b, atEOF := readCasesByte(t, r, fn, lineno)
if atEOF {
t.Helper()
t.Fatalf("%s:%d: unexpected EOF", fn, lineno)
}
return b
}
================================================
FILE: demangle.go
================================================
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package demangle defines functions that demangle GCC/LLVM
// C++ and Rust symbol names.
// This package recognizes names that were mangled according to the C++ ABI
// defined at http://codesourcery.com/cxx-abi/ and the Rust ABI
// defined at
// https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html
//
// Most programs will want to call Filter or ToString.
package demangle
import (
"errors"
"fmt"
"strings"
)
// ErrNotMangledName is returned by CheckedDemangle if the string does
// not appear to be a C++ symbol name.
var ErrNotMangledName = errors.New("not a C++ or Rust mangled name")
// Option is the type of demangler options.
type Option int
const (
// The NoParams option disables demangling of function parameters.
// It only omits the parameters of the function name being demangled,
// not the parameter types of other functions that may be mentioned.
// Using the option will speed up the demangler and cause it to
// use less memory.
NoParams Option = iota
// The NoTemplateParams option disables demangling of template parameters.
// This applies to both C++ and Rust.
NoTemplateParams
// The NoEnclosingParams option disables demangling of the function
// parameter types of the enclosing function when demangling a
// local name defined within a function.
NoEnclosingParams
// The NoClones option disables inclusion of clone suffixes.
// NoParams implies NoClones.
NoClones
// The NoRust option disables demangling of old-style Rust
// mangled names, which can be confused with C++ style mangled
// names. New style Rust mangled names are still recognized.
NoRust
// The Verbose option turns on more verbose demangling.
Verbose
// LLVMStyle tries to translate an AST to a string in the
// style of the LLVM demangler. This does not affect
// the parsing of the AST, only the conversion of the AST
// to a string.
LLVMStyle
)
// maxLengthShift is how we shift the MaxLength value.
const maxLengthShift = 16
// maxLengthMask is a mask for the maxLength value.
const maxLengthMask = 0x1f << maxLengthShift
// 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 {
if pow <= 0 || pow > 30 {
panic("demangle: invalid MaxLength value")
}
return Option(pow << maxLengthShift)
}
// isMaxLength reports whether an Option holds a maximum length.
func isMaxLength(opt Option) bool {
return opt&maxLengthMask != 0
}
// maxLength returns the maximum length stored in an Option.
func maxLength(opt Option) int {
return 1 << ((opt & maxLengthMask) >> maxLengthShift)
}
// 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 {
ret, err := ToString(name, options...)
if err != nil {
return name
}
return ret
}
// 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) {
if strings.HasPrefix(name, "_R") {
return rustToString(name, options)
}
// Check for an old-style Rust mangled name.
// It starts with _ZN and ends with "17h" followed by 16 hex digits
// followed by "E" followed by an optional suffix starting with "."
// (which we ignore).
if strings.HasPrefix(name, "_ZN") {
rname := name
if pos := strings.LastIndex(rname, "E."); pos > 0 {
rname = rname[:pos+1]
}
if strings.HasSuffix(rname, "E") && len(rname) > 23 && rname[len(rname)-20:len(rname)-17] == "17h" {
noRust := false
for _, o := range options {
if o == NoRust {
noRust = true
break
}
}
if !noRust {
s, ok := oldRustToString(rname, options)
if ok {
return s, nil
}
}
}
}
a, err := ToAST(name, options...)
if err != nil {
return "", err
}
return ASTToString(a, options...), nil
}
// 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) {
if strings.HasPrefix(name, "_Z") {
a, err := doDemangle(name[2:], options...)
return a, adjustErr(err, 2)
}
if strings.HasPrefix(name, "___Z") {
// clang extensions
block := strings.LastIndex(name, "_block_invoke")
if block == -1 {
return nil, ErrNotMangledName
}
a, err := doDemangle(name[4:block], options...)
if err != nil {
return a, adjustErr(err, 4)
}
name = strings.TrimPrefix(name[block:], "_block_invoke")
if len(name) > 0 && name[0] == '_' {
name = name[1:]
}
for len(name) > 0 && isDigit(name[0]) {
name = name[1:]
}
if len(name) > 0 && name[0] != '.' {
return nil, errors.New("unparsed characters at end of mangled name")
}
a = &Special{Prefix: "invocation function for block in ", Val: a}
return a, nil
}
const ctorDtorPrefix = "_GLOBAL_"
if strings.HasPrefix(name, ctorDtorPrefix) {
// The standard demangler ignores NoParams for global
// constructors. We are compatible.
i := 0
for i < len(options) {
if options[i] == NoParams {
options = append(options[:i:i], options[i+1:]...)
} else {
i++
}
}
a, err := globalCDtorName(name[len(ctorDtorPrefix):], options...)
return a, adjustErr(err, len(ctorDtorPrefix))
}
const allocTokenPrefix = "__alloc_token_"
if strings.HasPrefix(name, allocTokenPrefix) {
a, err := allocToken(name[len(allocTokenPrefix):], options...)
return a, adjustErr(err, len(allocTokenPrefix))
}
return nil, ErrNotMangledName
}
// 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) {
if len(name) < 4 {
return nil, ErrNotMangledName
}
switch name[0] {
case '.', '_', '$':
default:
return nil, ErrNotMangledName
}
var ctor bool
switch name[1] {
case 'I':
ctor = true
case 'D':
ctor = false
default:
return nil, ErrNotMangledName
}
if name[2] != '_' {
return nil, ErrNotMangledName
}
if !strings.HasPrefix(name[3:], "_Z") {
return &GlobalCDtor{Ctor: ctor, Key: &Name{Name: name}}, nil
} else {
a, err := doDemangle(name[5:], options...)
if err != nil {
return nil, adjustErr(err, 5)
}
return &GlobalCDtor{Ctor: ctor, Key: a}, nil
}
}
// allocToken handles Clang allocation token names,
// as described at https://clang.llvm.org/docs/AllocToken.html.
// Here name is the name after the __alloc_token_ prefix.
//
// As far as I can tell only a few such names are ever generated,
// so I don't know why they introduced a new mangling scheme,
// but it seems that they did.
func allocToken(name string, options ...Option) (AST, error) {
// Names look like __alloc_token_[num_]NAME
// We've skipped the __alloc_token_ already.
// The num is not included in the demangled name.
adj := 0
if len(name) > adj && isDigit(name[adj]) {
adj++
for len(name) > adj && isDigit(name[adj]) {
adj++
}
if len(name) <= adj || name[adj] != '_' {
return nil, ErrNotMangledName
}
adj++
}
if !strings.HasPrefix(name[adj:], "_Z") {
return nil, ErrNotMangledName
}
adj += 2
a, err := doDemangle(name[adj:], options...)
if err == nil {
a = &Clone{Base: a, Suffix: ".alloc_token"}
}
return a, adjustErr(err, adj)
}
// The doDemangle function is the entry point into the demangler proper.
func doDemangle(name string, options ...Option) (ret AST, err error) {
// When the demangling routines encounter an error, they panic
// with a value of type demangleErr.
defer func() {
if r := recover(); r != nil {
if de, ok := r.(demangleErr); ok {
ret = nil
err = de
return
}
panic(r)
}
}()
params := true
clones := true
verbose := false
for _, o := range options {
switch {
case o == NoParams:
params = false
clones = false
case o == NoClones:
clones = false
case o == Verbose:
verbose = true
case o == NoTemplateParams || o == NoEnclosingParams || o == LLVMStyle || isMaxLength(o):
// These are valid options but only affect
// printing of the AST.
case o == NoRust:
// Unimportant here.
default:
return nil, fmt.Errorf("unrecognized demangler option %v", o)
}
}
st := &state{str: name, verbose: verbose}
a := st.encoding(params, notForLocalName)
// Accept a clone suffix.
if clones {
for len(st.str) > 1 && st.str[0] == '.' && (isLower(st.str[1]) || st.str[1] == '_' || isDigit(st.str[1])) {
a = st.cloneSuffix(a)
}
}
if clones && len(st.str) > 0 {
st.fail("unparsed characters at end of mangled name")
}
return a, nil
}
// A state holds the current state of demangling a string.
type state struct {
str string // remainder of string to demangle
verbose bool // whether to use verbose demangling
off int // offset of str within original string
subs substitutions // substitutions
templates []*Template // templates being processed
// The number of entries in templates when we started parsing
// a lambda, plus 1 so that 0 means not parsing a lambda.
lambdaTemplateLevel int
parsingConstraint bool // whether parsing a constraint expression
// Counts of template parameters without template arguments,
// for lambdas.
typeTemplateParamCount int
nonTypeTemplateParamCount int
templateTemplateParamCount int
}
// copy returns a copy of the current state.
func (st *state) copy() *state {
n := new(state)
*n = *st
return n
}
// fail panics with demangleErr, to be caught in doDemangle.
func (st *state) fail(err string) {
panic(demangleErr{err: err, off: st.off})
}
// 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) {
if st.off < dec {
panic("internal error")
}
panic(demangleErr{err: err, off: st.off - dec})
}
// advance advances the current string offset.
func (st *state) advance(add int) {
if len(st.str) < add {
panic("internal error")
}
st.str = st.str[add:]
st.off += add
}
// checkChar requires that the next character in the string be c, and
// advances past it.
func (st *state) checkChar(c byte) {
if len(st.str) == 0 || st.str[0] != c {
panic("internal error")
}
st.advance(1)
}
// A demangleErr is an error at a specific offset in the mangled
// string.
type demangleErr struct {
err string
off int
}
// Error implements the builtin error interface for demangleErr.
func (de demangleErr) Error() string {
return fmt.Sprintf("%s at %d", de.err, de.off)
}
// adjustErr adjusts the position of err, if it is a demangleErr,
// and returns err.
func adjustErr(err error, adj int) error {
if err == nil {
return nil
}
if de, ok := err.(demangleErr); ok {
de.off += adj
return de
}
return err
}
type forLocalNameType int
const (
forLocalName forLocalNameType = iota
notForLocalName
)
// encoding parses:
//
// encoding ::= <(function) name> <bare-function-type>
// <(data) name>
// <special-name>
func (st *state) encoding(params bool, local forLocalNameType) AST {
if len(st.str) < 1 {
st.fail("expected encoding")
}
if st.str[0] == 'G' || st.str[0] == 'T' {
return st.specialName()
}
a, explicitObjectParameter := st.name()
a = simplify(a)
if !params {
// Don't demangle the parameters.
// Strip CV-qualifiers, as they apply to the 'this'
// parameter, and are not output by the standard
// demangler without parameters.
if mwq, ok := a.(*MethodWithQualifiers); ok {
a = mwq.Method
}
// If this is a local name, there may be CV-qualifiers
// on the name that really apply to the top level, and
// therefore must be discarded when discarding
// parameters. This can happen when parsing a class
// that is local to a function.
if q, ok := a.(*Qualified); ok && q.LocalName {
p := &q.Name
if da, ok := (*p).(*DefaultArg); ok {
p = &da.Arg
}
if mwq, ok := (*p).(*MethodWithQualifiers); ok {
*p = mwq.Method
}
}
return a
}
if len(st.str) == 0 || st.str[0] == 'E' {
// There are no parameters--this is a data symbol, not
// a function symbol.
return a
}
mwq, _ := a.(*MethodWithQualifiers)
var findTemplate func(AST) *Template
findTemplate = func(check AST) *Template {
switch check := check.(type) {
case *Template:
return check
case *Qualified:
if check.LocalName {
return findTemplate(check.Name)
} else if _, ok := check.Name.(*Constructor); ok {
return findTemplate(check.Name)
}
case *MethodWithQualifiers:
return findTemplate(check.Method)
case *Constructor:
if check.Base != nil {
return findTemplate(check.Base)
}
case *Constraint:
return findTemplate(check.Name)
}
return nil
}
template := findTemplate(a)
var oldLambdaTemplateLevel int
if template != nil {
st.templates = append(st.templates, template)
oldLambdaTemplateLevel = st.lambdaTemplateLevel
st.lambdaTemplateLevel = 0
}
// Checking for the enable_if attribute here is what the LLVM
// demangler does. This is not very general but perhaps it is
// sufficient.
const enableIfPrefix = "Ua9enable_ifI"
var (
enableIfArgs []AST
enableIfConstraint AST
)
if strings.HasPrefix(st.str, enableIfPrefix) {
st.advance(len(enableIfPrefix) - 1)
enableIfArgs, enableIfConstraint = st.templateArgs()
}
ft := st.bareFunctionType(hasReturnType(a), explicitObjectParameter)
var constraint AST
if len(st.str) > 0 && st.str[0] == 'Q' {
constraint = st.constraintExpr()
}
if template != nil {
st.templates = st.templates[:len(st.templates)-1]
st.lambdaTemplateLevel = oldLambdaTemplateLevel
}
ft = simplify(ft)
// For a local name, discard the return type, so that it
// doesn't get confused with the top level return type.
if local == forLocalName {
if functype, ok := ft.(*FunctionType); ok {
functype.ForLocalName = true
}
}
// Any top-level qualifiers belong to the function type.
if mwq != nil {
a = mwq.Method
mwq.Method = ft
ft = mwq
}
if q, ok := a.(*Qualified); ok && q.LocalName {
p := &q.Name
if da, ok := (*p).(*DefaultArg); ok {
p = &da.Arg
}
if mwq, ok := (*p).(*MethodWithQualifiers); ok {
*p = mwq.Method
mwq.Method = ft
ft = mwq
}
}
// Any top-level constraint belongs on the function type.
var forTemplateArgs bool
if c, ok := a.(*Constraint); ok && constraint == nil {
a = c.Name
constraint = c.Requires
forTemplateArgs = c.ForTemplateArgs
}
r := AST(&Typed{Name: a, Type: ft})
if len(enableIfArgs) > 0 {
r = &EnableIf{Type: r, Args: enableIfArgs}
r = st.maybeAddConstraint(r, enableIfConstraint)
}
if constraint != nil {
r = &Constraint{
Name: r,
Requires: constraint,
ForTemplateArgs: forTemplateArgs,
}
}
return r
}
// hasReturnType returns whether the mangled form of a will have a
// return type.
func hasReturnType(a AST) bool {
switch a := a.(type) {
case *Qualified:
if a.LocalName {
return hasReturnType(a.Name)
}
return false
case *Template:
return !isCDtorConversion(a.Name)
case *TypeWithQualifiers:
return hasReturnType(a.Base)
case *MethodWithQualifiers:
return hasReturnType(a.Method)
case *Constraint:
return hasReturnType(a.Name)
default:
return false
}
}
// isCDtorConversion returns when an AST is a constructor, a
// destructor, or a conversion operator.
func isCDtorConversion(a AST) bool {
switch a := a.(type) {
case *Qualified:
return isCDtorConversion(a.Name)
case *Constructor, *Destructor, *Cast:
return true
default:
return false
}
}
// taggedName parses:
//
// <tagged-name> ::= <name> B <source-name>
func (st *state) taggedName(a AST) AST {
for len(st.str) > 0 && st.str[0] == 'B' {
st.advance(1)
tag := st.sourceName()
a = &TaggedName{Name: a, Tag: tag}
}
return a
}
// 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) {
if len(st.str) < 1 {
st.fail("expected name")
}
var module AST
switch st.str[0] {
case 'N':
return st.nestedName()
case 'Z':
return st.localName()
case 'U':
a, isCast := st.unqualifiedName(nil)
if isCast {
st.setTemplate(a, nil)
}
return a, false
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(nil)
a = &Qualified{Scope: &Name{Name: "std"}, Name: a, LocalName: false}
} else {
a = st.substitution(false)
if mn, ok := a.(*ModuleName); ok {
module = mn
break
}
subst = true
}
var constraint AST
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)
}
var args []AST
args, constraint = 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)
}
a = st.maybeAddConstraint(a, constraint)
return a, false
}
a, isCast := st.unqualifiedName(module)
var constraint AST
if len(st.str) > 0 && st.str[0] == 'I' {
st.subs.add(a)
var args []AST
args, constraint = 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)
}
a = st.maybeAddConstraint(a, constraint)
return a, false
}
// 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) {
st.checkChar('N')
var q AST
var r string
explicitObjectParameter := false
if len(st.str) > 0 && st.str[0] == 'H' {
st.advance(1)
explicitObjectParameter = true
} else {
q = st.cvQualifiers()
r = st.refQualifier()
}
a := st.prefix()
if q != nil || r != "" {
a = &MethodWithQualifiers{Method: a, Qualifiers: q, RefQualifier: r}
}
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("expected E after nested name")
}
st.advance(1)
return a, explicitObjectParameter
}
// 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 {
var a AST
// The last name seen, for a constructor/destructor.
var last AST
var module AST
getLast := func(a AST) AST {
for {
if t, ok := a.(*Template); ok {
a = t.Name
} else if q, ok := a.(*Qualified); ok {
a = q.Name
} else if t, ok := a.(*TaggedName); ok {
a = t.Name
} else {
return a
}
}
}
var cast *Cast
for {
if len(st.str) == 0 {
st.fail("expected prefix")
}
var next AST
c := st.str[0]
if isDigit(c) || isLower(c) || c == 'U' || c == 'L' || c == 'F' || c == 'W' || (c == 'D' && len(st.str) > 1 && st.str[1] == 'C') {
un, isUnCast := st.unqualifiedName(module)
next = un
module = nil
if isUnCast {
if cast != nil {
st.fail("cast in scope of cast")
}
if m, ok := un.(*ModuleEntity); ok {
un = m.Name
}
for {
tn, ok := un.(*TaggedName)
if !ok {
break
}
un = tn.Name
}
if f, ok := un.(*Friend); ok {
un = f.Name
}
cast = un.(*Cast)
}
} else {
switch st.str[0] {
case 'C':
inheriting := false
st.advance(1)
if len(st.str) > 0 && st.str[0] == 'I' {
inheriting = true
st.advance(1)
}
if len(st.str) < 1 {
st.fail("expected constructor type")
}
if last == nil {
st.fail("constructor before name is seen")
}
switch st.str[0] {
// 0 is not used.
case '1', '2', '3', '4', '5':
default:
st.fail("unknown constructor type")
}
st.advance(1)
var base AST
if inheriting {
base = st.demangleType(false)
}
next = &Constructor{
Name: getLast(last),
Base: base,
}
if len(st.str) > 0 && st.str[0] == 'B' {
next = st.taggedName(next)
}
case 'D':
if len(st.str) > 1 && (st.str[1] == 'T' || st.str[1] == 't') {
next = st.demangleType(false)
} else {
if len(st.str) < 2 {
st.fail("expected destructor type")
}
if last == nil {
st.fail("destructor before name is seen")
}
switch st.str[1] {
// 3 is not used.
case '0', '1', '2', '4', '5':
default:
st.fail("unknown destructor type")
}
st.advance(2)
next = &Destructor{Name: getLast(last)}
if len(st.str) > 0 && st.str[0] == 'B' {
next = st.taggedName(next)
}
}
case 'S':
next = st.substitution(true)
if mn, ok := next.(*ModuleName); ok {
module = mn
next = nil
}
case 'I':
if a == nil {
st.fail("unexpected template arguments")
}
args, constraint := st.templateArgs()
tmpl := &Template{Name: a, Args: args}
if cast != nil {
st.setTemplate(cast, tmpl)
st.clearTemplateArgs(args)
cast = nil
}
a = nil
next = st.maybeAddConstraint(tmpl, constraint)
case 'T':
next = st.templateParam()
case 'E':
if a == nil {
st.fail("expected prefix")
}
if cast != nil {
var toTmpl *Template
if castTempl, ok := cast.To.(*Template); ok {
toTmpl = castTempl
}
st.setTemplate(cast, toTmpl)
}
return a
case 'M':
if a == nil {
st.fail("unexpected lambda initializer")
}
// This is the initializer scope for a
// lambda. We don't need to record
// it. The normal code will treat the
// variable has a type scope, which
// gives appropriate output.
st.advance(1)
continue
case 'J':
// It appears that in some cases clang
// can emit a J for a template arg
// without the expected I. I don't
// know when this happens, but I've
// seen it in some large C++ programs.
if a == nil {
st.fail("unexpected template arguments")
}
var args []AST
for len(st.str) == 0 || st.str[0] != 'E' {
arg := st.templateArg(nil)
args = append(args, arg)
}
st.advance(1)
tmpl := &Template{Name: a, Args: args}
if cast != nil {
st.setTemplate(cast, tmpl)
st.clearTemplateArgs(args)
cast = nil
}
a = nil
next = tmpl
default:
st.fail("unrecognized letter in prefix")
}
}
if next == nil {
continue
}
last = next
if a == nil {
a = next
} else {
a = &Qualified{Scope: a, Name: next, LocalName: false}
}
if c != 'S' && (len(st.str) == 0 || st.str[0] != 'E') {
st.subs.add(a)
}
}
}
// 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) {
module = st.moduleName(module)
if len(st.str) < 1 {
st.fail("expected unqualified name")
}
friend := false
if len(st.str) > 0 && st.str[0] == 'F' {
st.advance(1)
friend = true
if len(st.str) < 1 {
st.fail("expected unqualified name")
}
}
var a AST
isCast = false
c := st.str[0]
if isDigit(c) {
a = st.sourceName()
} else if isLower(c) {
a, _ = st.operatorName(false)
if _, ok := a.(*Cast); ok {
isCast = true
}
if op, ok := a.(*Operator); ok && op.Name == `operator"" ` {
n := st.sourceName()
a = &Unary{Op: op, Expr: n, Suffix: false, SizeofType: false}
}
} else if c == 'D' && len(st.str) > 1 && st.str[1] == 'C' {
var bindings []AST
st.advance(2)
for {
binding := st.sourceName()
bindings = append(bindings, binding)
if len(st.str) > 0 && st.str[0] == 'E' {
st.advance(1)
break
}
}
a = &StructuredBindings{Bindings: bindings}
} else {
switch c {
case 'C', 'D':
st.fail("constructor/destructor not in nested name")
case 'L':
st.advance(1)
a = st.sourceName()
a = st.discriminator(a)
case 'U':
if len(st.str) < 2 {
st.advance(1)
st.fail("expected closure or unnamed type")
}
c := st.str[1]
switch c {
case 'b':
st.advance(2)
st.compactNumber()
a = &Name{Name: "'block-literal'"}
case 'e':
a = st.unnamedEnum()
case 'l':
a = st.closureTypeName()
case 't':
a = st.unnamedTypeName()
default:
st.advance(1)
st.fail("expected closure or unnamed type")
}
default:
st.fail("expected unqualified name")
}
}
if module != nil {
a = &ModuleEntity{Module: module, Name: a}
}
if len(st.str) > 0 && st.str[0] == 'B' {
a = st.taggedName(a)
}
if friend {
a = &Friend{Name: a}
}
return a, isCast
}
// sourceName parses:
//
// <source-name> ::= <(positive length) number> <identifier>
// identifier ::= <(unqualified source code identifier)>
func (st *state) sourceName() AST {
val := st.number()
if val <= 0 {
st.fail("expected positive number")
}
if len(st.str) < val {
st.fail("not enough characters for identifier")
}
id := st.str[:val]
st.advance(val)
// Look for GCC encoding of anonymous namespace, and make it
// more friendly.
const anonPrefix = "_GLOBAL_"
if strings.HasPrefix(id, anonPrefix) && len(id) > len(anonPrefix)+2 {
c1 := id[len(anonPrefix)]
c2 := id[len(anonPrefix)+1]
if (c1 == '.' || c1 == '_' || c1 == '$') && c2 == 'N' {
id = "(anonymous namespace)"
}
}
n := &Name{Name: id}
return n
}
// 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 {
ret := parent
for len(st.str) > 0 && st.str[0] == 'W' {
st.advance(1)
isPartition := false
if len(st.str) > 0 && st.str[0] == 'P' {
st.advance(1)
isPartition = true
}
name := st.sourceName()
ret = &ModuleName{
Parent: ret,
Name: name,
IsPartition: isPartition,
}
st.subs.add(ret)
}
return ret
}
// number parses:
//
// number ::= [n] <(non-negative decimal integer)>
func (st *state) number() int {
neg := false
if len(st.str) > 0 && st.str[0] == 'n' {
neg = true
st.advance(1)
}
if len(st.str) == 0 || !isDigit(st.str[0]) {
st.fail("missing number")
}
val := 0
for len(st.str) > 0 && isDigit(st.str[0]) {
// Number picked to ensure we can't overflow with 32-bit int.
// Any very large number here is bogus.
if val >= 0x80000000/10-10 {
st.fail("numeric overflow")
}
val = val*10 + int(st.str[0]-'0')
st.advance(1)
}
if neg {
val = -val
}
return val
}
// seqID parses:
//
// <seq-id> ::= <0-9A-Z>+
//
// We expect this to be followed by an underscore.
func (st *state) seqID(eofOK bool) int {
if len(st.str) > 0 && st.str[0] == '_' {
st.advance(1)
return 0
}
id := 0
for {
if len(st.str) == 0 {
if eofOK {
return id + 1
}
st.fail("missing end to sequence ID")
}
// Don't overflow a 32-bit int.
if id >= 0x80000000/36-36 {
st.fail("sequence ID overflow")
}
c := st.str[0]
if c == '_' {
st.advance(1)
return id + 1
}
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 sequence ID")
}
st.advance(1)
}
}
// An operator is the demangled name, and the number of arguments it
// takes in an expression.
type operator struct {
name string
args int
prec precedence
}
// The operators map maps the mangled operator names to information
// about them.
var operators = map[string]operator{
"aN": {"&=", 2, precAssign},
"aS": {"=", 2, precAssign},
"aa": {"&&", 2, precLogicalAnd},
"ad": {"&", 1, precUnary},
"an": {"&", 2, precAnd},
"at": {"alignof ", 1, precUnary},
"aw": {"co_await ", 1, precPrimary},
"az": {"alignof ", 1, precUnary},
"cc": {"const_cast", 2, precPostfix},
"cl": {"()", 2, precPostfix},
// cp is not in the ABI but is used by clang "when the call
// would use ADL except for being parenthesized."
// The trailing space indicates this to the printer.
"cp": {"() ", 2, precPostfix},
"cm": {",", 2, precComma},
"co": {"~", 1, precUnary},
"dV": {"/=", 2, precAssign},
"dX": {"[...]=", 3, precAssign},
"da": {"delete[] ", 1, precUnary},
"dc": {"dynamic_cast", 2, precPostfix},
"de": {"*", 1, precUnary},
"di": {"=", 2, precAssign},
"dl": {"delete ", 1, precUnary},
"ds": {".*", 2, precPtrMem},
"dt": {".", 2, precPostfix},
"dv": {"/", 2, precAssign},
"dx": {"]=", 2, precAssign},
"eO": {"^=", 2, precAssign},
"eo": {"^", 2, precXor},
"eq": {"==", 2, precEqual},
"fl": {"...", 2, precPrimary},
"fr": {"...", 2, precPrimary},
"fL": {"...", 3, precPrimary},
"fR": {"...", 3, precPrimary},
"ge": {">=", 2, precRel},
"gs": {"::", 1, precUnary},
"gt": {">", 2, precRel},
"ix": {"[]", 2, precPostfix},
"lS": {"<<=", 2, precAssign},
"le": {"<=", 2, precRel},
"li": {`operator"" `, 1, precUnary},
"ls": {"<<", 2, precShift},
"lt": {"<", 2, precRel},
"mI": {"-=", 2, precAssign},
"mL": {"*=", 2, precAssign},
"mi": {"-", 2, precAdd},
"ml": {"*", 2, precMul},
"mm": {"--", 1, precPostfix},
"na": {"new[]", 3, precUnary},
"ne": {"!=", 2, precEqual},
"ng": {"-", 1, precUnary},
"nt": {"!", 1, precUnary},
"nw": {"new", 3, precUnary},
"nx": {"noexcept", 1, precUnary},
"oR": {"|=", 2, precAssign},
"oo": {"||", 2, precLogicalOr},
"or": {"|", 2, precOr},
"pL": {"+=", 2, precAssign},
"pl": {"+", 2, precAdd},
"pm": {"->*", 2, precPtrMem},
"pp": {"++", 1, precPostfix},
"ps": {"+", 1, precUnary},
"pt": {"->", 2, precPostfix},
"qu": {"?", 3, precCond},
"rM": {"%=", 2, precAssign},
"rS": {">>=", 2, precAssign},
"rc": {"reinterpret_cast", 2, precPostfix},
"rm": {"%", 2, precMul},
"rs": {">>", 2, precShift},
"sP": {"sizeof...", 1, precUnary},
"sZ": {"sizeof...", 1, precUnary},
"sc": {"static_cast", 2, precPostfix},
"ss": {"<=>", 2, precSpaceship},
"st": {"sizeof ", 1, precUnary},
"sz": {"sizeof ", 1, precUnary},
"te": {"typeid ", 1, precPostfix},
"ti": {"typeid ", 1, precPostfix},
"tr": {"throw", 0, precPrimary},
"tw": {"throw ", 1, precUnary},
}
// 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) {
if len(st.str) < 2 {
st.fail("missing operator code")
}
code := st.str[:2]
st.advance(2)
if code[0] == 'v' && isDigit(code[1]) {
name := st.sourceName()
return &Operator{Name: name.(*Name).Name}, int(code[1] - '0')
} else if code == "cv" {
// Push a nil on templates to indicate that template
// parameters will have their template filled in
// later.
if !inExpression {
st.templates = append(st.templates, nil)
}
t := st.demangleType(!inExpression)
if !inExpression {
st.templates = st.templates[:len(st.templates)-1]
}
return &Cast{To: t}, 1
} else if op, ok := operators[code]; ok {
return &Operator{Name: op.name, precedence: op.prec}, op.args
} else {
st.failEarlier("unrecognized operator code", 2)
panic("not reached")
}
}
// 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) {
st.checkChar('Z')
fn := st.encoding(true, forLocalName)
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("expected E after local name")
}
st.advance(1)
if len(st.str) > 0 && st.str[0] == 's' {
st.advance(1)
var n AST = &Name{Name: "string literal"}
n = st.discriminator(n)
return &Qualified{Scope: fn, Name: n, LocalName: true}, false
} else {
num := -1
if len(st.str) > 0 && st.str[0] == 'd' {
// Default argument scope.
st.advance(1)
num = st.compactNumber()
}
n, explicitObjectParameter := st.name()
n = st.discriminator(n)
if num >= 0 {
n = &DefaultArg{Num: num, Arg: n}
}
return &Qualified{Scope: fn, Name: n, LocalName: true}, explicitObjectParameter
}
}
// Parse a Java resource special-name.
func (st *state) javaResource() AST {
off := st.off
ln := st.number()
if ln <= 1 {
st.failEarlier("java resource length less than 1", st.off-off)
}
if len(st.str) == 0 || st.str[0] != '_' {
st.fail("expected _ after number")
}
st.advance(1)
ln--
if len(st.str) < ln {
st.fail("not enough characters for java resource length")
}
str := st.str[:ln]
final := ""
st.advance(ln)
for i := 0; i < len(str); i++ {
if str[i] != '$' {
final += string(str[i])
} else {
if len(str) <= i+1 {
st.failEarlier("java resource escape at end of string", 1)
}
i++
r, ok := map[byte]string{
'S': "/",
'_': ".",
'$': "$",
}[str[i]]
if !ok {
st.failEarlier("unrecognized java resource escape", ln-i-1)
}
final += r
}
}
return &Special{Prefix: "java resource ", Val: &Name{Name: final}}
}
// 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 {
if st.str[0] == 'T' {
st.advance(1)
if len(st.str) == 0 {
st.fail("expected special name code")
}
c := st.str[0]
st.advance(1)
switch c {
case 'V':
t := st.demangleType(false)
return &Special{Prefix: "vtable for ", Val: t}
case 'T':
t := st.demangleType(false)
return &Special{Prefix: "VTT for ", Val: t}
case 'I':
t := st.demangleType(false)
return &Special{Prefix: "typeinfo for ", Val: t}
case 'S':
t := st.demangleType(false)
return &Special{Prefix: "typeinfo name for ", Val: t}
case 'A':
t := st.templateArg(nil)
return &Special{Prefix: "template parameter object for ", Val: t}
case 'h':
st.callOffset('h')
v := st.encoding(true, notForLocalName)
return &Special{Prefix: "non-virtual thunk to ", Val: v}
case 'v':
st.callOffset('v')
v := st.encoding(true, notForLocalName)
return &Special{Prefix: "virtual thunk to ", Val: v}
case 'c':
st.callOffset(0)
st.callOffset(0)
v := st.encoding(true, notForLocalName)
return &Special{Prefix: "covariant return thunk to ", Val: v}
case 'C':
derived := st.demangleType(false)
off := st.off
offset := st.number()
if offset < 0 {
st.failEarlier("expected positive offset", st.off-off)
}
if len(st.str) == 0 || st.str[0] != '_' {
st.fail("expected _ after number")
}
st.advance(1)
base := st.demangleType(false)
return &Special2{Prefix: "construction vtable for ", Val1: base, Middle: "-in-", Val2: derived}
case 'F':
t := st.demangleType(false)
return &Special{Prefix: "typeinfo fn for ", Val: t}
case 'J':
t := st.demangleType(false)
return &Special{Prefix: "java Class for ", Val: t}
case 'H':
n, _ := st.name()
return &Special{Prefix: "TLS init function for ", Val: n}
case 'W':
n, _ := st.name()
return &Special{Prefix: "TLS wrapper function for ", Val: n}
default:
st.fail("unrecognized special T name code")
panic("not reached")
}
} else {
st.checkChar('G')
if len(st.str) == 0 {
st.fail("expected special name code")
}
c := st.str[0]
st.advance(1)
switch c {
case 'V':
n, _ := st.name()
return &Special{Prefix: "guard variable for ", Val: n}
case 'R':
n, _ := st.name()
st.seqID(true)
return &Special{Prefix: "reference temporary for ", Val: n}
case 'A':
v := st.encoding(true, notForLocalName)
return &Special{Prefix: "hidden alias for ", Val: v}
case 'T':
if len(st.str) == 0 {
st.fail("expected special GT name code")
}
c := st.str[0]
st.advance(1)
v := st.encoding(true, notForLocalName)
switch c {
case 'n':
return &Special{Prefix: "non-transaction clone for ", Val: v}
default:
// The proposal is that different
// letters stand for different types
// of transactional cloning. Treat
// them all the same for now.
fallthrough
case 't':
return &Special{Prefix: "transaction clone for ", Val: v}
}
case 'r':
return st.javaResource()
case 'I':
module := st.moduleName(nil)
if module == nil {
st.fail("expected module after GI")
}
return &Special{Prefix: "initializer for module ", Val: module}
default:
st.fail("unrecognized special G name code")
panic("not reached")
}
}
}
// 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) {
if c == 0 {
if len(st.str) == 0 {
st.fail("missing call offset")
}
c = st.str[0]
st.advance(1)
}
switch c {
case 'h':
st.number()
case 'v':
st.number()
if len(st.str) == 0 || st.str[0] != '_' {
st.fail("expected _ after number")
}
st.advance(1)
st.number()
default:
st.failEarlier("unrecognized call offset code", 1)
}
if len(st.str) == 0 || st.str[0] != '_' {
st.fail("expected _ after call offset")
}
st.advance(1)
}
// builtinTypes maps the type letter to the type name.
var builtinTypes = map[byte]string{
'a': "signed char",
'b': "bool",
'c': "char",
'd': "double",
'e': "long double",
'f': "float",
'g': "__float128",
'h': "unsigned char",
'i': "int",
'j': "unsigned int",
'l': "long",
'm': "unsigned long",
'n': "__int128",
'o': "unsigned __int128",
's': "short",
't': "unsigned short",
'v': "void",
'w': "wchar_t",
'x': "long long",
'y': "unsigned long long",
'z': "...",
}
// 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 {
if len(st.str) == 0 {
st.fail("expected type")
}
addSubst := true
q := st.cvQualifiers()
if q != nil {
if len(st.str) == 0 {
st.fail("expected type")
}
// CV-qualifiers before a function type apply to
// 'this', so avoid adding the unqualified function
// type to the substitution list.
if st.str[0] == 'F' {
addSubst = false
}
}
var ret AST
// Use correct substitution for a template parameter.
var sub AST
if btype, ok := builtinTypes[st.str[0]]; ok {
ret = &BuiltinType{Name: btype}
st.advance(1)
if q != nil {
ret = &TypeWithQualifiers{Base: ret, Qualifiers: q}
st.subs.add(ret)
}
return ret
}
c := st.str[0]
switch c {
case 'u':
st.advance(1)
ret = st.sourceName()
if len(st.str) > 0 && st.str[0] == 'I' {
st.advance(1)
base := st.demangleType(false)
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("expected E after transformed type")
}
st.advance(1)
ret = &TransformedType{Name: ret.(*Name).Name, Base: base}
}
case 'F':
ret = st.functionType()
case 'N', 'W', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
ret, _ = st.name()
case 'A':
ret = st.arrayType(isCast)
case 'M':
ret = st.pointerToMemberType(isCast)
case 'T':
if len(st.str) > 1 && (st.str[1] == 's' || st.str[1] == 'u' || st.str[1] == 'e') {
c = st.str[1]
st.advance(2)
ret, _ = st.name()
var kind string
switch c {
case 's':
kind = "struct"
case 'u':
kind = "union"
case 'e':
kind = "enum"
}
ret = &ElaboratedType{Kind: kind, Type: ret}
break
}
ret = st.templateParam()
if len(st.str) > 0 && st.str[0] == 'I' {
// See the function comment to explain this.
if !isCast {
st.subs.add(ret)
ret = st.template(ret)
} else {
ret = st.demangleCastTemplateArgs(ret, true)
}
}
case 'S':
// If this is a special substitution, then it
// is the start of <class-enum-type>.
var c2 byte
if len(st.str) > 1 {
c2 = st.str[1]
}
if isDigit(c2) || c2 == '_' || isUpper(c2) {
ret = st.substitution(false)
if _, ok := ret.(*ModuleName); ok {
var isCast bool
ret, isCast = st.unqualifiedName(ret)
if isCast {
st.setTemplate(ret, nil)
}
st.subs.add(ret)
}
if len(st.str) == 0 || st.str[0] != 'I' {
addSubst = false
} else {
// See the function comment to explain this.
if _, ok := ret.(*TemplateParam); !ok || !isCast {
ret = st.template(ret)
} else {
next := st.demangleCastTemplateArgs(ret, false)
if next == ret {
addSubst = false
}
ret = next
}
}
} else {
ret, _ = st.name()
// This substitution is not itself a
// substitution candidate, unless template
// arguments were added.
if ret == subAST[c2] || ret == verboseAST[c2] {
addSubst = false
}
}
case 'O', 'P', 'R', 'C', 'G':
st.advance(1)
t := st.demangleType(isCast)
switch c {
case 'O':
ret = &RvalueReferenceType{Base: t}
case 'P':
ret = &PointerType{Base: t}
case 'R':
ret = &ReferenceType{Base: t}
case 'C':
ret = &ComplexType{Base: t}
case 'G':
ret = &ImaginaryType{Base: t}
}
case 'U':
if len(st.str) < 2 {
st.fail("expected source name or unnamed type")
}
switch st.str[1] {
case 'e':
ret = st.unnamedEnum()
addSubst = false
case 'l':
ret = st.closureTypeName()
addSubst = false
case 't':
ret = st.unnamedTypeName()
addSubst = false
default:
st.advance(1)
n := st.sourceName()
if len(st.str) > 0 && st.str[0] == 'I' {
n = st.template(n)
}
t := st.demangleType(isCast)
ret = &VendorQualifier{Qualifier: n, Type: t}
}
case 'D':
st.advance(1)
if len(st.str) == 0 {
st.fail("expected D code for type")
}
addSubst = false
c2 := st.str[0]
st.advance(1)
fixedPrefix := func(c byte) (string, bool) {
switch c {
case 's':
return "short ", true
case 't':
return "unsigned short ", true
case 'i':
return "", true
case 'j':
return "unsigned ", true
case 'l':
return "long ", true
case 'm':
return "unsigned long ", true
default:
return "", false
}
}
switch c2 {
case 'T', 't':
// decltype(expression)
ret = st.expression()
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("expected E after expression in type")
}
st.advance(1)
ret = &Decltype{Expr: ret}
addSubst = true
case 'p':
t := st.demangleType(isCast)
pack := st.findArgumentPack(t)
ret = &PackExpansion{Base: t, Pack: pack}
addSubst = true
case 'a':
ret = &Name{Name: "auto"}
case 'c':
ret = &Name{Name: "decltype(auto)"}
case 'f':
ret = &BuiltinType{Name: "decimal32"}
case 'd':
ret = &BuiltinType{Name: "decimal64"}
case 'e':
ret = &BuiltinType{Name: "decimal128"}
case 'h':
ret = &BuiltinType{Name: "half"}
case 'u':
ret = &BuiltinType{Name: "char8_t"}
case 's':
ret = &BuiltinType{Name: "char16_t"}
case 'i':
ret = &BuiltinType{Name: "char32_t"}
case 'n':
ret = &BuiltinType{Name: "decltype(nullptr)"}
case 'F':
accum := false
bits := 0
if len(st.str) > 0 && isDigit(st.str[0]) {
accum = true
bits = st.number()
}
if len(st.str) > 0 && st.str[0] == '_' {
if bits == 0 {
st.fail("expected non-zero number of bits")
}
st.advance(1)
ret = &BinaryFP{Bits: bits, Suffix: ""}
} else if len(st.str) > 0 && st.str[0] == 'x' {
if bits == 0 {
st.fail("expected non-zero number of bits")
}
st.advance(1)
ret = &BinaryFP{Bits: bits, Suffix: "x"}
} else if len(st.str) > 0 && st.str[0] == 'b' {
if bits != 16 {
st.fail("expected bits to be 16 for std::bfloat16_t")
}
st.advance(1)
ret = &BuiltinType{Name: "std::bfloat16_t"}
} else {
base := st.demangleType(isCast)
if len(st.str) > 0 && isDigit(st.str[0]) {
// We don't care about the bits.
st.number()
}
sat := false
if len(st.str) > 0 {
if st.str[0] == 's' {
sat = true
}
st.advance(1)
}
ret = &FixedType{Base: base, Accum: accum, Sat: sat}
}
case 'v':
ret = st.vectorType(isCast)
addSubst = true
case 'B', 'U':
signed := c2 == 'B'
var size AST
if len(st.str) > 0 && isDigit(st.str[0]) {
bits := st.number()
size = &Name{Name: fmt.Sprintf("%d", bits)}
} else {
size = st.expression()
}
if len(st.str) == 0 || st.str[0] != '_' {
st.fail("expected _ after _BitInt size")
}
st.advance(1)
ret = &BitIntType{Size: size, Signed: signed}
addSubst = true
case 'k':
constraint, _ := st.name()
ret = &SuffixType{
Base: constraint,
Suffix: "auto",
}
case 'K':
constraint, _ := st.name()
ret = &SuffixType{
Base: constraint,
Suffix: "decltype(auto)",
}
case 'A', 'R':
if len(st.str) == 0 {
st.fail("missing D{A,R} code in type")
}
prefix, ok := fixedPrefix(st.str[0])
if !ok {
st.fail("unrecognized D{A,R} code in type")
}
st.advance(1)
switch c2 {
case 'A':
ret = &BuiltinType{Name: prefix + "_Accum"}
case 'R':
ret = &BuiltinType{Name: prefix + "_Fract"}
default:
panic("internal error")
}
case 'S':
if len(st.str) < 3 {
st.fail("missing DS code in type")
}
if st.str[0] != 'D' {
st.fail("unrecognized DS code in type")
}
var suffix string
switch st.str[1] {
case 'A':
suffix = "_Accum"
case 'R':
suffix = "_Fract"
default:
st.fail("unrecognized DSD code in type")
}
prefix, ok := fixedPrefix(st.str[2])
if !ok {
st.fail("unrecognized DSD{A,R} code in type")
}
st.advance(3)
ret = &BuiltinType{Name: "_Sat " + prefix + suffix}
default:
st.fail("unrecognized D code in type")
}
default:
st.fail("unrecognized type code")
}
if addSubst {
if sub != nil {
st.subs.add(sub)
} else {
st.subs.add(ret)
}
}
if q != nil {
if _, ok := ret.(*FunctionType); ok {
ret = &MethodWithQualifiers{Method: ret, Qualifiers: q, RefQualifier: ""}
} else if mwq, ok := ret.(*MethodWithQualifiers); ok {
// Merge adjacent qualifiers. This case
// happens with a function with a trailing
// ref-qualifier.
mwq.Qualifiers = mergeQualifiers(q, mwq.Qualifiers)
} else {
// Merge adjacent qualifiers. This case
// happens with multi-dimensional array types.
if qsub, ok := ret.(*TypeWithQualifiers); ok {
q = mergeQualifiers(q, qsub.Qualifiers)
ret = qsub.Base
}
ret = &TypeWithQualifiers{Base: ret, Qualifiers: q}
}
st.subs.add(ret)
}
return ret
}
// 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 {
save := st.copy()
var (
args []AST
constraint AST
)
failed := false
func() {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(demangleErr); ok {
failed = true
} else {
panic(r)
}
}
}()
args, constraint = st.templateArgs()
}()
if !failed && len(st.str) > 0 && st.str[0] == 'I' {
if addSubst {
st.subs.add(tp)
}
ret := &Template{Name: tp, Args: args}
return st.maybeAddConstraint(ret, constraint)
}
// Reset back to before we started reading the template arguments.
// They will be read again by st.prefix.
*st = *save
return tp
}
// mergeQualifiers merges two qualifier lists into one.
func mergeQualifiers(q1AST, q2AST AST) AST {
if q1AST == nil {
return q2AST
}
if q2AST == nil {
return q1AST
}
q1 := q1AST.(*Qualifiers)
m := make(map[string]bool)
for _, qualAST := range q1.Qualifiers {
qual := qualAST.(*Qualifier)
if len(qual.Exprs) == 0 {
m[qual.Name] = true
}
}
rq := q1.Qualifiers
for _, qualAST := range q2AST.(*Qualifiers).Qualifiers {
qual := qualAST.(*Qualifier)
if len(qual.Exprs) > 0 {
rq = append(rq, qualAST)
} else if !m[qual.Name] {
rq = append(rq, qualAST)
m[qual.Name] = true
}
}
q1.Qualifiers = rq
return q1
}
// qualifiers maps from the character used in the mangled name to the
// string to print.
var qualifiers = map[byte]string{
'r': "restrict",
'V': "volatile",
'K': "const",
}
// cvQualifiers parses:
//
// <CV-qualifiers> ::= [r] [V] [K]
func (st *state) cvQualifiers() AST {
var q []AST
qualLoop:
for len(st.str) > 0 {
if qv, ok := qualifiers[st.str[0]]; ok {
qual := &Qualifier{Name: qv}
q = append([]AST{qual}, q...)
st.advance(1)
} else if len(st.str) > 1 && st.str[0] == 'D' {
var qual AST
switch st.str[1] {
case 'x':
qual = &Qualifier{Name: "transaction_safe"}
st.advance(2)
case 'o':
qual = &Qualifier{Name: "noexcept"}
st.advance(2)
case 'O':
st.advance(2)
expr := st.expression()
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("expected E after computed noexcept expression")
}
st.advance(1)
qual = &Qualifier{Name: "noexcept", Exprs: []AST{expr}}
case 'w':
st.advance(2)
parmlist := st.parmlist(false)
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("expected E after throw parameter list")
}
st.advance(1)
qual = &Qualifier{Name: "throw", Exprs: parmlist}
default:
break qualLoop
}
q = append([]AST{qual}, q...)
} else {
break
}
}
if len(q) == 0 {
return nil
}
return &Qualifiers{Qualifiers: q}
}
// refQualifier parses:
//
// <ref-qualifier> ::= R
// ::= O
func (st *state) refQualifier() string {
if len(st.str) > 0 {
switch st.str[0] {
case 'R':
st.advance(1)
return "&"
case 'O':
st.advance(1)
return "&&"
}
}
return ""
}
// parmlist parses:
//
// <type>+
func (st *state) parmlist(explicitObjectParameter bool) []AST {
var ret []AST
for {
if len(st.str) < 1 {
break
}
if st.str[0] == 'E' || st.str[0] == '.' {
break
}
if (st.str[0] == 'R' || st.str[0] == 'O') && len(st.str) > 1 && st.str[1] == 'E' {
// This is a function ref-qualifier.
break
}
if st.str[0] == 'Q' {
// This is a requires clause.
break
}
ptype := st.demangleType(false)
if len(ret) == 0 && explicitObjectParameter {
ptype = &ExplicitObjectParameter{Base: ptype}
}
ret = append(ret, ptype)
}
// There should always be at least one type. A function that
// takes no arguments will have a single parameter type
// "void".
if len(ret) == 0 {
st.fail("expected at least one type in type list")
}
// Omit a single parameter type void.
if len(ret) == 1 {
if bt, ok := ret[0].(*BuiltinType); ok && bt.Name == "void" {
ret = nil
}
}
return ret
}
// functionType parses:
//
// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
func (st *state) functionType() AST {
st.checkChar('F')
if len(st.str) > 0 && st.str[0] == 'Y' {
// Function has C linkage. We don't print this.
st.advance(1)
}
ret := st.bareFunctionType(true, false)
r := st.refQualifier()
if r != "" {
ret = &MethodWithQualifiers{Method: ret, Qualifiers: nil, RefQualifier: r}
}
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("expected E after function type")
}
st.advance(1)
return ret
}
// bareFunctionType parses:
//
// <bare-function-type> ::= [J]<type>+
func (st *state) bareFunctionType(hasReturnType, explicitObjectParameter bool) AST {
if len(st.str) > 0 && st.str[0] == 'J' {
hasReturnType = true
st.advance(1)
}
var returnType AST
if hasReturnType {
returnType = st.demangleType(false)
}
types := st.parmlist(explicitObjectParameter)
return &FunctionType{
Return: returnType,
Args: types,
ForLocalName: false, // may be set later in encoding
}
}
// arrayType parses:
//
// <array-type> ::= A <(positive dimension) number> _ <(element) type>
// ::= A [<(dimension) expression>] _ <(element) type>
func (st *state) arrayType(isCast bool) AST {
st.checkChar('A')
if len(st.str) == 0 {
st.fail("missing array dimension")
}
var dim AST
if st.str[0] == '_' {
dim = &Name{Name: ""}
} else if isDigit(st.str[0]) {
i := 1
for len(st.str) > i && isDigit(st.str[i]) {
i++
}
dim = &Name{Name: st.str[:i]}
st.advance(i)
} else {
dim = st.expression()
}
if len(st.str) == 0 || st.str[0] != '_' {
st.fail("expected _ after dimension")
}
st.advance(1)
t := st.demangleType(isCast)
arr := &ArrayType{Dimension: dim, Element: t}
// Qualifiers on the element of an array type go on the whole
// array type.
if q, ok := arr.Element.(*TypeWithQualifiers); ok {
return &TypeWithQualifiers{Base: &ArrayType{Dimension: dim, Element: q.Base}, Qualifiers: q.Qualifiers}
}
return arr
}
// vectorType parses:
//
// <vector-type> ::= Dv <number> _ <type>
// ::= Dv _ <expression> _ <type>
func (st *state) vectorType(isCast bool) AST {
if len(st.str) == 0 {
st.fail("expected vector dimension")
}
var dim AST
if st.str[0] == '_' {
st.advance(1)
dim = st.expression()
} else {
num := st.number()
dim = &Name{Name: fmt.Sprintf("%d", num)}
}
if len(st.str) == 0 || st.str[0] != '_' {
st.fail("expected _ after vector dimension")
}
st.advance(1)
t := st.demangleType(isCast)
return &VectorType{Dimension: dim, Base: t}
}
// pointerToMemberType parses:
//
// <pointer-to-member-type> ::= M <(class) type> <(member) type>
func (st *state) pointerToMemberType(isCast bool) AST {
st.checkChar('M')
cl := st.demangleType(false)
// The ABI says, "The type of a non-static member function is
// considered to be different, for the purposes of
// substitution, from the type of a namespace-scope or static
// member function whose type appears similar. The types of
// two non-static member functions are considered to be
// different, for the purposes of substitution, if the
// functions are members of different classes. In other words,
// for the purposes of substitution, the class of which the
// function is a member is considered part of the type of
// function."
//
// For a pointer to member function, this call to demangleType
// will end up adding a (possibly qualified) non-member
// function type to the substitution table, which is not
// correct; however, the member function type will never be
// used in a substitution, so putting the wrong type in the
// substitution table is harmless.
mem := st.demangleType(isCast)
return &PtrMem{Class: cl, Member: mem}
}
// compactNumber parses:
//
// <non-negative number> _
func (st *state) compactNumber() int {
if len(st.str) == 0 {
st.fail("missing index")
}
if st.str[0] == '_' {
st.advance(1)
return 0
} else if st.str[0] == 'n' {
st.fail("unexpected negative number")
}
n := st.number()
if len(st.str) == 0 || st.str[0] != '_' {
st.fail("missing underscore after number")
}
st.advance(1)
return n + 1
}
// 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 {
off := st.off
str := st.str
st.checkChar('T')
level := 0
if len(st.str) > 0 && st.str[0] == 'L' {
st.advance(1)
level = st.compactNumber()
}
n := st.compactNumber()
// We don't try to substitute template parameters in a
// constraint expression.
if st.parsingConstraint {
return &Name{Name: str[:st.off-1-off]}
}
if level >= len(st.templates) {
if st.lambdaTemplateLevel > 0 && level == st.lambdaTemplateLevel-1 {
// Lambda auto params are mangled as template params.
// See https://gcc.gnu.org/PR78252.
return &LambdaAuto{Index: n}
}
st.failEarlier(fmt.Sprintf("template parameter is not in scope of template (level %d >= %d)", level, len(st.templates)), st.off-off)
}
template := st.templates[level]
if template == nil {
// We are parsing a cast operator. If the cast is
// itself a template, then this is a forward
// reference. Fill it in later.
return &TemplateParam{Index: n, Template: nil}
}
if n >= len(template.Args) {
if st.lambdaTemplateLevel > 0 && level == st.lambdaTemplateLevel-1 {
// Lambda auto params are mangled as template params.
// See https://gcc.gnu.org/PR78252.
return &LambdaAuto{Index: n}
}
st.failEarlier(fmt.Sprintf("template index out of range (%d >= %d)", n, len(template.Args)), st.off-off)
}
return &TemplateParam{Index: n, Template: template}
}
// 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) {
seen := make(map[AST]bool)
a.Traverse(func(a AST) bool {
switch a := a.(type) {
case *TemplateParam:
if a.Template != nil {
if tmpl != nil {
st.fail("duplicate template parameters")
}
return false
}
if tmpl == nil {
st.fail("cast template parameter not in scope of template")
}
if a.Index >= len(tmpl.Args) {
st.fail(fmt.Sprintf("cast template index out of range (%d >= %d)", a.Index, len(tmpl.Args)))
}
a.Template = tmpl
return false
case *Closure:
// There are no template params in closure types.
// https://gcc.gnu.org/PR78252.
if tmpl == nil {
a.Traverse(func(a AST) bool {
if tmplParam, ok := a.(*TemplateParam); ok && tmplParam.Template == nil {
st.fail("cast template parameter not in scope of template")
}
if seen[a] {
return false
}
seen[a] = true
return true
})
}
return false
default:
if seen[a] {
return false
}
seen[a] = true
return true
}
})
}
// 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) {
for _, a := range args {
st.setTemplate(a, nil)
}
}
// templateArgs parses:
//
// <template-args> ::= I <template-arg>+ E
//
// This returns the template arguments and an optional constraint.
func (st *state) templateArgs() ([]AST, AST) {
if len(st.str) == 0 || (st.str[0] != 'I' && st.str[0] != 'J') {
panic("internal error")
}
st.advance(1)
var (
ret []AST
constraint AST
)
for len(st.str) == 0 || st.str[0] != 'E' {
arg := st.templateArg(ret)
ret = append(ret, arg)
if len(st.str) > 0 && st.str[0] == 'Q' {
constraint = st.constraintExpr()
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("expected end of template arguments after constraint")
}
}
}
st.advance(1)
return ret, constraint
}
// 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 {
if len(st.str) == 0 {
st.fail("missing template argument")
}
switch st.str[0] {
case 'X':
st.advance(1)
expr := st.expression()
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("missing end of expression")
}
st.advance(1)
return expr
case 'L':
return st.exprPrimary()
case 'I', 'J':
args, constraint := st.templateArgs()
ret := &ArgumentPack{Args: args}
return st.maybeAddConstraint(ret, constraint)
case 'T':
var arg byte
if len(st.str) > 1 {
arg = st.str[1]
}
switch arg {
case 'y', 'n', 't', 'p', 'k':
off := st.off
// Apparently template references in the
// template parameter refer to previous
// arguments in the same template.
template := &Template{Args: prev}
st.templates = append(st.templates, template)
param, _ := st.templateParamDecl()
st.templates = st.templates[:len(st.templates)-1]
if param == nil {
st.failEarlier("expected template parameter as template argument", st.off-off)
}
arg := st.templateArg(nil)
return &TemplateParamQualifiedArg{Param: param, Arg: arg}
}
return st.demangleType(false)
default:
return st.demangleType(false)
}
}
// maybeAddConstraint adds a constraint to an AST, if constraint is not nil.
// This is only called with a constraint found at the end of
// template arguments.
func (st *state) maybeAddConstraint(a, constraint AST) AST {
if constraint == nil {
return a
}
return &Constraint{
Name: a,
Requires: constraint,
ForTemplateArgs: true,
}
}
// template parses template arguments into a Template with a given name.
func (st *state) template(name AST) AST {
args, constraint := st.templateArgs()
ret := &Template{Name: name, Args: args}
return st.maybeAddConstraint(ret, constraint)
}
// exprList parses a sequence of expressions up to a terminating character.
func (st *state) exprList(stop byte) AST {
if len(st.str) > 0 && st.str[0] == stop {
st.advance(1)
return &ExprList{Exprs: nil}
}
var exprs []AST
for {
e := st.expression()
exprs = append(exprs, e)
if len(st.str) > 0 && st.str[0] == stop {
st.advance(1)
break
}
}
return &ExprList{Exprs: exprs}
}
// 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>
//
gitextract_d03jdduc/
├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── ast.go
├── ast_test.go
├── c++filt.go
├── cases_test.go
├── demangle.go
├── demangle_test.go
├── expected_test.go
├── fuzz_test.go
├── go.mod
├── rust.go
├── rust_expected_test.go
└── testdata/
├── DemangleTestCases.inc
├── demangle-expected
├── rust-demangle-expected
└── rust.test
SYMBOL INDEX (685 symbols across 10 files)
FILE: ast.go
type AST (line 16) | type AST interface
function ASTToString (line 40) | func ASTToString(a AST, options ...Option) string {
type printState (line 74) | type printState struct
method writeByte (line 111) | func (ps *printState) writeByte(b byte) {
method writeString (line 117) | func (ps *printState) writeString(s string) {
method print (line 125) | func (ps *printState) print(a AST) {
method printList (line 155) | func (ps *printState) printList(args []AST, skip func(AST) bool) {
method startScope (line 189) | func (ps *printState) startScope(b byte) {
method endScope (line 195) | func (ps *printState) endScope(b byte) {
method printInner (line 5402) | func (ps *printState) printInner(prefixOnly bool) []AST {
method printOneInner (line 5422) | func (ps *printState) printOneInner(save *[]AST) {
method isEmpty (line 5445) | func (ps *printState) isEmpty(a AST) bool {
type precedence (line 202) | type precedence
constant precPrimary (line 206) | precPrimary precedence = iota
constant precPostfix (line 207) | precPostfix
constant precUnary (line 208) | precUnary
constant precCast (line 209) | precCast
constant precPtrMem (line 210) | precPtrMem
constant precMul (line 211) | precMul
constant precAdd (line 212) | precAdd
constant precShift (line 213) | precShift
constant precSpaceship (line 214) | precSpaceship
constant precRel (line 215) | precRel
constant precEqual (line 216) | precEqual
constant precAnd (line 217) | precAnd
constant precXor (line 218) | precXor
constant precOr (line 219) | precOr
constant precLogicalAnd (line 220) | precLogicalAnd
constant precLogicalOr (line 221) | precLogicalOr
constant precCond (line 222) | precCond
constant precAssign (line 223) | precAssign
constant precComma (line 224) | precComma
constant precDefault (line 225) | precDefault
type hasPrec (line 230) | type hasPrec interface
type Name (line 235) | type Name struct
method print (line 239) | func (n *Name) print(ps *printState) {
method Traverse (line 243) | func (n *Name) Traverse(fn func(AST) bool) {
method Copy (line 247) | func (n *Name) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 254) | func (n *Name) GoString() string {
method goString (line 258) | func (n *Name) goString(indent int, field string) string {
method prec (line 262) | func (n *Name) prec() precedence {
type Typed (line 267) | type Typed struct
method print (line 272) | func (t *Typed) print(ps *printState) {
method printInner (line 288) | func (t *Typed) printInner(ps *printState) {
method Traverse (line 292) | func (t *Typed) Traverse(fn func(AST) bool) {
method Copy (line 299) | func (t *Typed) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 321) | func (t *Typed) GoString() string {
method goString (line 325) | func (t *Typed) goString(indent int, field string) string {
type Qualified (line 332) | type Qualified struct
method print (line 344) | func (q *Qualified) print(ps *printState) {
method Traverse (line 350) | func (q *Qualified) Traverse(fn func(AST) bool) {
method Copy (line 357) | func (q *Qualified) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 379) | func (q *Qualified) GoString() string {
method goString (line 383) | func (q *Qualified) goString(indent int, field string) string {
method prec (line 393) | func (q *Qualified) prec() precedence {
type Template (line 398) | type Template struct
method print (line 403) | func (t *Template) print(ps *printState) {
method Traverse (line 435) | func (t *Template) Traverse(fn func(AST) bool) {
method Copy (line 444) | func (t *Template) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 473) | func (t *Template) GoString() string {
method goString (line 477) | func (t *Template) goString(indent int, field string) string {
type TemplateParam (line 496) | type TemplateParam struct
method print (line 501) | func (tp *TemplateParam) print(ps *printState) {
method Traverse (line 511) | func (tp *TemplateParam) Traverse(fn func(AST) bool) {
method Copy (line 516) | func (tp *TemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) A...
method GoString (line 523) | func (tp *TemplateParam) GoString() string {
method goString (line 527) | func (tp *TemplateParam) goString(indent int, field string) string {
type LambdaAuto (line 532) | type LambdaAuto struct
method print (line 536) | func (la *LambdaAuto) print(ps *printState) {
method Traverse (line 546) | func (la *LambdaAuto) Traverse(fn func(AST) bool) {
method Copy (line 550) | func (la *LambdaAuto) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 557) | func (la *LambdaAuto) GoString() string {
method goString (line 561) | func (la *LambdaAuto) goString(indent int, field string) string {
type TemplateParamQualifiedArg (line 568) | type TemplateParamQualifiedArg struct
method print (line 573) | func (tpqa *TemplateParamQualifiedArg) print(ps *printState) {
method Traverse (line 581) | func (tpqa *TemplateParamQualifiedArg) Traverse(fn func(AST) bool) {
method Copy (line 588) | func (tpqa *TemplateParamQualifiedArg) Copy(fn func(AST) AST, skip fun...
method GoString (line 610) | func (tpqa *TemplateParamQualifiedArg) GoString() string {
method goString (line 614) | func (tpqa *TemplateParamQualifiedArg) goString(indent int, field stri...
type Qualifiers (line 621) | type Qualifiers struct
method print (line 625) | func (qs *Qualifiers) print(ps *printState) {
method Traverse (line 636) | func (qs *Qualifiers) Traverse(fn func(AST) bool) {
method Copy (line 644) | func (qs *Qualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 669) | func (qs *Qualifiers) GoString() string {
method goString (line 673) | func (qs *Qualifiers) goString(indent int, field string) string {
type Qualifier (line 683) | type Qualifier struct
method print (line 688) | func (q *Qualifier) print(ps *printState) {
method Traverse (line 707) | func (q *Qualifier) Traverse(fn func(AST) bool) {
method Copy (line 715) | func (q *Qualifier) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 740) | func (q *Qualifier) GoString() string {
method goString (line 744) | func (q *Qualifier) goString(indent int, field string) string {
type TypeWithQualifiers (line 756) | type TypeWithQualifiers struct
method print (line 761) | func (twq *TypeWithQualifiers) print(ps *printState) {
method printInner (line 779) | func (twq *TypeWithQualifiers) printInner(ps *printState) {
method Traverse (line 784) | func (twq *TypeWithQualifiers) Traverse(fn func(AST) bool) {
method Copy (line 790) | func (twq *TypeWithQualifiers) Copy(fn func(AST) AST, skip func(AST) b...
method GoString (line 812) | func (twq *TypeWithQualifiers) GoString() string {
method goString (line 816) | func (twq *TypeWithQualifiers) goString(indent int, field string) stri...
type MethodWithQualifiers (line 823) | type MethodWithQualifiers struct
method print (line 829) | func (mwq *MethodWithQualifiers) print(ps *printState) {
method printInner (line 846) | func (mwq *MethodWithQualifiers) printInner(ps *printState) {
method Traverse (line 857) | func (mwq *MethodWithQualifiers) Traverse(fn func(AST) bool) {
method Copy (line 863) | func (mwq *MethodWithQualifiers) Copy(fn func(AST) AST, skip func(AST)...
method GoString (line 888) | func (mwq *MethodWithQualifiers) GoString() string {
method goString (line 892) | func (mwq *MethodWithQualifiers) goString(indent int, field string) st...
type BuiltinType (line 908) | type BuiltinType struct
method print (line 912) | func (bt *BuiltinType) print(ps *printState) {
method Traverse (line 920) | func (bt *BuiltinType) Traverse(fn func(AST) bool) {
method Copy (line 924) | func (bt *BuiltinType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 931) | func (bt *BuiltinType) GoString() string {
method goString (line 935) | func (bt *BuiltinType) goString(indent int, field string) string {
method prec (line 939) | func (bt *BuiltinType) prec() precedence {
function printBase (line 945) | func printBase(ps *printState, qual, base AST) {
type PointerType (line 955) | type PointerType struct
method print (line 959) | func (pt *PointerType) print(ps *printState) {
method printInner (line 963) | func (pt *PointerType) printInner(ps *printState) {
method Traverse (line 967) | func (pt *PointerType) Traverse(fn func(AST) bool) {
method Copy (line 973) | func (pt *PointerType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 988) | func (pt *PointerType) GoString() string {
method goString (line 992) | func (pt *PointerType) goString(indent int, field string) string {
type ReferenceType (line 998) | type ReferenceType struct
method print (line 1002) | func (rt *ReferenceType) print(ps *printState) {
method printInner (line 1006) | func (rt *ReferenceType) printInner(ps *printState) {
method Traverse (line 1010) | func (rt *ReferenceType) Traverse(fn func(AST) bool) {
method Copy (line 1016) | func (rt *ReferenceType) Copy(fn func(AST) AST, skip func(AST) bool) A...
method GoString (line 1031) | func (rt *ReferenceType) GoString() string {
method goString (line 1035) | func (rt *ReferenceType) goString(indent int, field string) string {
type RvalueReferenceType (line 1041) | type RvalueReferenceType struct
method print (line 1045) | func (rt *RvalueReferenceType) print(ps *printState) {
method printInner (line 1049) | func (rt *RvalueReferenceType) printInner(ps *printState) {
method Traverse (line 1053) | func (rt *RvalueReferenceType) Traverse(fn func(AST) bool) {
method Copy (line 1059) | func (rt *RvalueReferenceType) Copy(fn func(AST) AST, skip func(AST) b...
method GoString (line 1074) | func (rt *RvalueReferenceType) GoString() string {
method goString (line 1078) | func (rt *RvalueReferenceType) goString(indent int, field string) stri...
type ComplexType (line 1084) | type ComplexType struct
method print (line 1088) | func (ct *ComplexType) print(ps *printState) {
method printInner (line 1092) | func (ct *ComplexType) printInner(ps *printState) {
method Traverse (line 1096) | func (ct *ComplexType) Traverse(fn func(AST) bool) {
method Copy (line 1102) | func (ct *ComplexType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1117) | func (ct *ComplexType) GoString() string {
method goString (line 1121) | func (ct *ComplexType) goString(indent int, field string) string {
type ImaginaryType (line 1127) | type ImaginaryType struct
method print (line 1131) | func (it *ImaginaryType) print(ps *printState) {
method printInner (line 1135) | func (it *ImaginaryType) printInner(ps *printState) {
method Traverse (line 1139) | func (it *ImaginaryType) Traverse(fn func(AST) bool) {
method Copy (line 1145) | func (it *ImaginaryType) Copy(fn func(AST) AST, skip func(AST) bool) A...
method GoString (line 1160) | func (it *ImaginaryType) GoString() string {
method goString (line 1164) | func (it *ImaginaryType) goString(indent int, field string) string {
type SuffixType (line 1170) | type SuffixType struct
method print (line 1175) | func (st *SuffixType) print(ps *printState) {
method printInner (line 1179) | func (st *SuffixType) printInner(ps *printState) {
method Traverse (line 1184) | func (st *SuffixType) Traverse(fn func(AST) bool) {
method Copy (line 1190) | func (st *SuffixType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1205) | func (st *SuffixType) GoString() string {
method goString (line 1209) | func (st *SuffixType) goString(indent int, field string) string {
type TransformedType (line 1215) | type TransformedType struct
method print (line 1220) | func (tt *TransformedType) print(ps *printState) {
method Traverse (line 1227) | func (tt *TransformedType) Traverse(fn func(AST) bool) {
method Copy (line 1233) | func (tt *TransformedType) Copy(fn func(AST) AST, skip func(AST) bool)...
method GoString (line 1248) | func (tt *TransformedType) GoString() string {
method goString (line 1252) | func (tt *TransformedType) goString(indent int, field string) string {
type VendorQualifier (line 1258) | type VendorQualifier struct
method print (line 1263) | func (vq *VendorQualifier) print(ps *printState) {
method printInner (line 1276) | func (vq *VendorQualifier) printInner(ps *printState) {
method Traverse (line 1281) | func (vq *VendorQualifier) Traverse(fn func(AST) bool) {
method Copy (line 1288) | func (vq *VendorQualifier) Copy(fn func(AST) AST, skip func(AST) bool)...
method GoString (line 1310) | func (vq *VendorQualifier) GoString() string {
method goString (line 1314) | func (vq *VendorQualifier) goString(indent int, field string) string {
type ArrayType (line 1321) | type ArrayType struct
method print (line 1326) | func (at *ArrayType) print(ps *printState) {
method printInner (line 1337) | func (at *ArrayType) printInner(ps *printState) {
method printDimension (line 1342) | func (at *ArrayType) printDimension(ps *printState) {
method Traverse (line 1371) | func (at *ArrayType) Traverse(fn func(AST) bool) {
method Copy (line 1378) | func (at *ArrayType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1400) | func (at *ArrayType) GoString() string {
method goString (line 1404) | func (at *ArrayType) goString(indent int, field string) string {
type FunctionType (line 1411) | type FunctionType struct
method print (line 1421) | func (ft *FunctionType) print(ps *printState) {
method printInner (line 1441) | func (ft *FunctionType) printInner(ps *printState) {
method printArgs (line 1447) | func (ft *FunctionType) printArgs(ps *printState) {
method Traverse (line 1499) | func (ft *FunctionType) Traverse(fn func(AST) bool) {
method Copy (line 1510) | func (ft *FunctionType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1548) | func (ft *FunctionType) GoString() string {
method goString (line 1552) | func (ft *FunctionType) goString(indent int, field string) string {
type FunctionParam (line 1579) | type FunctionParam struct
method print (line 1583) | func (fp *FunctionParam) print(ps *printState) {
method Traverse (line 1597) | func (fp *FunctionParam) Traverse(fn func(AST) bool) {
method Copy (line 1601) | func (fp *FunctionParam) Copy(fn func(AST) AST, skip func(AST) bool) A...
method GoString (line 1608) | func (fp *FunctionParam) GoString() string {
method goString (line 1612) | func (fp *FunctionParam) goString(indent int, field string) string {
method prec (line 1616) | func (fp *FunctionParam) prec() precedence {
type PtrMem (line 1621) | type PtrMem struct
method print (line 1626) | func (pm *PtrMem) print(ps *printState) {
method printInner (line 1634) | func (pm *PtrMem) printInner(ps *printState) {
method Traverse (line 1642) | func (pm *PtrMem) Traverse(fn func(AST) bool) {
method Copy (line 1649) | func (pm *PtrMem) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1671) | func (pm *PtrMem) GoString() string {
method goString (line 1675) | func (pm *PtrMem) goString(indent int, field string) string {
type FixedType (line 1682) | type FixedType struct
method print (line 1688) | func (ft *FixedType) print(ps *printState) {
method Traverse (line 1705) | func (ft *FixedType) Traverse(fn func(AST) bool) {
method Copy (line 1711) | func (ft *FixedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1726) | func (ft *FixedType) GoString() string {
method goString (line 1730) | func (ft *FixedType) goString(indent int, field string) string {
type BinaryFP (line 1737) | type BinaryFP struct
method print (line 1742) | func (bfp *BinaryFP) print(ps *printState) {
method Traverse (line 1746) | func (bfp *BinaryFP) Traverse(fn func(AST) bool) {
method Copy (line 1750) | func (bfp *BinaryFP) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1757) | func (bfp *BinaryFP) GoString() string {
method goString (line 1761) | func (bfp *BinaryFP) goString(indent int, field string) string {
type BitIntType (line 1766) | type BitIntType struct
method print (line 1771) | func (bt *BitIntType) print(ps *printState) {
method Traverse (line 1781) | func (bt *BitIntType) Traverse(fn func(AST) bool) {
method Copy (line 1787) | func (bt *BitIntType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1802) | func (bt *BitIntType) GoString() string {
method goString (line 1806) | func (bt *BitIntType) goString(indent int, field string) string {
type VectorType (line 1813) | type VectorType struct
method print (line 1818) | func (vt *VectorType) print(ps *printState) {
method printInner (line 1826) | func (vt *VectorType) printInner(ps *printState) {
method Traverse (line 1838) | func (vt *VectorType) Traverse(fn func(AST) bool) {
method Copy (line 1845) | func (vt *VectorType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1867) | func (vt *VectorType) GoString() string {
method goString (line 1871) | func (vt *VectorType) goString(indent int, field string) string {
type ElaboratedType (line 1878) | type ElaboratedType struct
method print (line 1883) | func (et *ElaboratedType) print(ps *printState) {
method Traverse (line 1889) | func (et *ElaboratedType) Traverse(fn func(AST) bool) {
method Copy (line 1895) | func (et *ElaboratedType) Copy(fn func(AST) AST, skip func(AST) bool) ...
method GoString (line 1910) | func (et *ElaboratedType) GoString() string {
method goString (line 1914) | func (et *ElaboratedType) goString(indent int, field string) string {
type Decltype (line 1920) | type Decltype struct
method print (line 1924) | func (dt *Decltype) print(ps *printState) {
method Traverse (line 1934) | func (dt *Decltype) Traverse(fn func(AST) bool) {
method Copy (line 1940) | func (dt *Decltype) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1955) | func (dt *Decltype) GoString() string {
method goString (line 1959) | func (dt *Decltype) goString(indent int, field string) string {
type Operator (line 1965) | type Operator struct
method print (line 1970) | func (op *Operator) print(ps *printState) {
method Traverse (line 1980) | func (op *Operator) Traverse(fn func(AST) bool) {
method Copy (line 1984) | func (op *Operator) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 1991) | func (op *Operator) GoString() string {
method goString (line 1995) | func (op *Operator) goString(indent int, field string) string {
method prec (line 1999) | func (op *Operator) prec() precedence {
type Constructor (line 2004) | type Constructor struct
method print (line 2009) | func (c *Constructor) print(ps *printState) {
method Traverse (line 2014) | func (c *Constructor) Traverse(fn func(AST) bool) {
method Copy (line 2023) | func (c *Constructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 2048) | func (c *Constructor) GoString() string {
method goString (line 2052) | func (c *Constructor) goString(indent int, field string) string {
type Destructor (line 2063) | type Destructor struct
method print (line 2067) | func (d *Destructor) print(ps *printState) {
method Traverse (line 2072) | func (d *Destructor) Traverse(fn func(AST) bool) {
method Copy (line 2078) | func (d *Destructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 2093) | func (d *Destructor) GoString() string {
method goString (line 2097) | func (d *Destructor) goString(indent int, field string) string {
type GlobalCDtor (line 2102) | type GlobalCDtor struct
method print (line 2107) | func (gcd *GlobalCDtor) print(ps *printState) {
method Traverse (line 2118) | func (gcd *GlobalCDtor) Traverse(fn func(AST) bool) {
method Copy (line 2124) | func (gcd *GlobalCDtor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 2139) | func (gcd *GlobalCDtor) GoString() string {
method goString (line 2143) | func (gcd *GlobalCDtor) goString(indent int, field string) string {
type TaggedName (line 2149) | type TaggedName struct
method print (line 2154) | func (t *TaggedName) print(ps *printState) {
method Traverse (line 2161) | func (t *TaggedName) Traverse(fn func(AST) bool) {
method Copy (line 2168) | func (t *TaggedName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 2190) | func (t *TaggedName) GoString() string {
method goString (line 2194) | func (t *TaggedName) goString(indent int, field string) string {
type PackExpansion (line 2201) | type PackExpansion struct
method print (line 2206) | func (pe *PackExpansion) print(ps *printState) {
method Traverse (line 2221) | func (pe *PackExpansion) Traverse(fn func(AST) bool) {
method Copy (line 2228) | func (pe *PackExpansion) Copy(fn func(AST) AST, skip func(AST) bool) A...
method GoString (line 2243) | func (pe *PackExpansion) GoString() string {
method goString (line 2247) | func (pe *PackExpansion) goString(indent int, field string) string {
type ArgumentPack (line 2253) | type ArgumentPack struct
method print (line 2257) | func (ap *ArgumentPack) print(ps *printState) {
method Traverse (line 2266) | func (ap *ArgumentPack) Traverse(fn func(AST) bool) {
method Copy (line 2274) | func (ap *ArgumentPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 2299) | func (ap *ArgumentPack) GoString() string {
method goString (line 2303) | func (ap *ArgumentPack) goString(indent int, field string) string {
type SizeofPack (line 2316) | type SizeofPack struct
method print (line 2320) | func (sp *SizeofPack) print(ps *printState) {
method Traverse (line 2331) | func (sp *SizeofPack) Traverse(fn func(AST) bool) {
method Copy (line 2336) | func (sp *SizeofPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 2347) | func (sp *SizeofPack) GoString() string {
method goString (line 2351) | func (sp *SizeofPack) goString(indent int, field string) string {
type SizeofArgs (line 2357) | type SizeofArgs struct
method print (line 2361) | func (sa *SizeofArgs) print(ps *printState) {
method Traverse (line 2375) | func (sa *SizeofArgs) Traverse(fn func(AST) bool) {
method Copy (line 2383) | func (sa *SizeofArgs) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 2408) | func (sa *SizeofArgs) GoString() string {
method goString (line 2412) | func (sa *SizeofArgs) goString(indent int, field string) string {
type TemplateParamName (line 2429) | type TemplateParamName struct
method print (line 2434) | func (tpn *TemplateParamName) print(ps *printState) {
method Traverse (line 2445) | func (tpn *TemplateParamName) Traverse(fn func(AST) bool) {
method Copy (line 2449) | func (tpn *TemplateParamName) Copy(fn func(AST) AST, skip func(AST) bo...
method GoString (line 2456) | func (tpn *TemplateParamName) GoString() string {
method goString (line 2460) | func (tpn *TemplateParamName) goString(indent int, field string) string {
type TypeTemplateParam (line 2466) | type TypeTemplateParam struct
method print (line 2470) | func (ttp *TypeTemplateParam) print(ps *printState) {
method Traverse (line 2484) | func (ttp *TypeTemplateParam) Traverse(fn func(AST) bool) {
method Copy (line 2490) | func (ttp *TypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bo...
method GoString (line 2505) | func (ttp *TypeTemplateParam) GoString() string {
method goString (line 2509) | func (ttp *TypeTemplateParam) goString(indent int, field string) string {
type NonTypeTemplateParam (line 2516) | type NonTypeTemplateParam struct
method print (line 2521) | func (nttp *NonTypeTemplateParam) print(ps *printState) {
method printInner (line 2533) | func (nttp *NonTypeTemplateParam) printInner(ps *printState) {
method Traverse (line 2537) | func (nttp *NonTypeTemplateParam) Traverse(fn func(AST) bool) {
method Copy (line 2544) | func (nttp *NonTypeTemplateParam) Copy(fn func(AST) AST, skip func(AST...
method GoString (line 2566) | func (nttp *NonTypeTemplateParam) GoString() string {
method goString (line 2570) | func (nttp *NonTypeTemplateParam) goString(indent int, field string) s...
type TemplateTemplateParam (line 2578) | type TemplateTemplateParam struct
method print (line 2584) | func (ttp *TemplateTemplateParam) print(ps *printState) {
method Traverse (line 2618) | func (ttp *TemplateTemplateParam) Traverse(fn func(AST) bool) {
method Copy (line 2630) | func (ttp *TemplateTemplateParam) Copy(fn func(AST) AST, skip func(AST...
method GoString (line 2680) | func (ttp *TemplateTemplateParam) GoString() string {
method goString (line 2684) | func (ttp *TemplateTemplateParam) goString(indent int, field string) s...
type ConstrainedTypeTemplateParam (line 2705) | type ConstrainedTypeTemplateParam struct
method print (line 2710) | func (cttp *ConstrainedTypeTemplateParam) print(ps *printState) {
method printInner (line 2720) | func (cttp *ConstrainedTypeTemplateParam) printInner(ps *printState) {
method Traverse (line 2724) | func (cttp *ConstrainedTypeTemplateParam) Traverse(fn func(AST) bool) {
method Copy (line 2731) | func (cttp *ConstrainedTypeTemplateParam) Copy(fn func(AST) AST, skip ...
method GoString (line 2753) | func (cttp *ConstrainedTypeTemplateParam) GoString() string {
method goString (line 2757) | func (cttp *ConstrainedTypeTemplateParam) goString(indent int, field s...
type TemplateParamPack (line 2765) | type TemplateParamPack struct
method print (line 2769) | func (tpp *TemplateParamPack) print(ps *printState) {
method printInner (line 2789) | func (tpp *TemplateParamPack) printInner(ps *printState) {
method Traverse (line 2796) | func (tpp *TemplateParamPack) Traverse(fn func(AST) bool) {
method Copy (line 2802) | func (tpp *TemplateParamPack) Copy(fn func(AST) AST, skip func(AST) bo...
method GoString (line 2817) | func (tpp *TemplateParamPack) GoString() string {
method goString (line 2821) | func (tpp *TemplateParamPack) goString(indent int, field string) string {
type Cast (line 2827) | type Cast struct
method print (line 2831) | func (c *Cast) print(ps *printState) {
method Traverse (line 2836) | func (c *Cast) Traverse(fn func(AST) bool) {
method Copy (line 2842) | func (c *Cast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 2857) | func (c *Cast) GoString() string {
method goString (line 2861) | func (c *Cast) goString(indent int, field string) string {
method prec (line 2866) | func (c *Cast) prec() precedence {
function parenthesize (line 2872) | func parenthesize(ps *printState, val AST) {
type Nullary (line 2898) | type Nullary struct
method print (line 2902) | func (n *Nullary) print(ps *printState) {
method Traverse (line 2910) | func (n *Nullary) Traverse(fn func(AST) bool) {
method Copy (line 2916) | func (n *Nullary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 2931) | func (n *Nullary) GoString() string {
method goString (line 2935) | func (n *Nullary) goString(indent int, field string) string {
type Unary (line 2941) | type Unary struct
method print (line 2948) | func (u *Unary) print(ps *printState) {
method Traverse (line 3048) | func (u *Unary) Traverse(fn func(AST) bool) {
method Copy (line 3055) | func (u *Unary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 3077) | func (u *Unary) GoString() string {
method goString (line 3081) | func (u *Unary) goString(indent int, field string) string {
method prec (line 3094) | func (u *Unary) prec() precedence {
function isDesignatedInitializer (line 3103) | func isDesignatedInitializer(x AST) bool {
type Binary (line 3127) | type Binary struct
method print (line 3133) | func (b *Binary) print(ps *printState) {
method Traverse (line 3295) | func (b *Binary) Traverse(fn func(AST) bool) {
method Copy (line 3303) | func (b *Binary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 3329) | func (b *Binary) GoString() string {
method goString (line 3333) | func (b *Binary) goString(indent int, field string) string {
method prec (line 3340) | func (b *Binary) prec() precedence {
type Trinary (line 3348) | type Trinary struct
method print (line 3355) | func (t *Trinary) print(ps *printState) {
method Traverse (line 3445) | func (t *Trinary) Traverse(fn func(AST) bool) {
method Copy (line 3454) | func (t *Trinary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 3484) | func (t *Trinary) GoString() string {
method goString (line 3488) | func (t *Trinary) goString(indent int, field string) string {
type Fold (line 3497) | type Fold struct
method print (line 3504) | func (f *Fold) print(ps *printState) {
method Traverse (line 3566) | func (f *Fold) Traverse(fn func(AST) bool) {
method Copy (line 3576) | func (f *Fold) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 3605) | func (f *Fold) GoString() string {
method goString (line 3609) | func (f *Fold) goString(indent int, field string) string {
type Subobject (line 3627) | type Subobject struct
method print (line 3635) | func (so *Subobject) print(ps *printState) {
method Traverse (line 3642) | func (so *Subobject) Traverse(fn func(AST) bool) {
method Copy (line 3649) | func (so *Subobject) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 3677) | func (so *Subobject) GoString() string {
method goString (line 3681) | func (so *Subobject) goString(indent int, field string) string {
type PtrMemCast (line 3700) | type PtrMemCast struct
method print (line 3706) | func (pmc *PtrMemCast) print(ps *printState) {
method Traverse (line 3714) | func (pmc *PtrMemCast) Traverse(fn func(AST) bool) {
method Copy (line 3721) | func (pmc *PtrMemCast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 3747) | func (pmc *PtrMemCast) GoString() string {
method goString (line 3751) | func (pmc *PtrMemCast) goString(indent int, field string) string {
type New (line 3760) | type New struct
method print (line 3767) | func (n *New) print(ps *printState) {
method Traverse (line 3792) | func (n *New) Traverse(fn func(AST) bool) {
method Copy (line 3805) | func (n *New) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 3841) | func (n *New) GoString() string {
method goString (line 3845) | func (n *New) goString(indent int, field string) string {
type Literal (line 3864) | type Literal struct
method print (line 3889) | func (l *Literal) print(ps *printState) {
method Traverse (line 3936) | func (l *Literal) Traverse(fn func(AST) bool) {
method Copy (line 3942) | func (l *Literal) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 3957) | func (l *Literal) GoString() string {
method goString (line 3961) | func (l *Literal) goString(indent int, field string) string {
method prec (line 3971) | func (l *Literal) prec() precedence {
type StringLiteral (line 3976) | type StringLiteral struct
method print (line 3980) | func (sl *StringLiteral) print(ps *printState) {
method Traverse (line 3986) | func (sl *StringLiteral) Traverse(fn func(AST) bool) {
method Copy (line 3992) | func (sl *StringLiteral) Copy(fn func(AST) AST, skip func(AST) bool) A...
method GoString (line 4007) | func (sl *StringLiteral) GoString() string {
method goString (line 4011) | func (sl *StringLiteral) goString(indent int, field string) string {
type LambdaExpr (line 4017) | type LambdaExpr struct
method print (line 4021) | func (le *LambdaExpr) print(ps *printState) {
method Traverse (line 4029) | func (le *LambdaExpr) Traverse(fn func(AST) bool) {
method Copy (line 4035) | func (le *LambdaExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4050) | func (le *LambdaExpr) GoString() string {
method goString (line 4054) | func (le *LambdaExpr) goString(indent int, field string) string {
type ExprList (line 4061) | type ExprList struct
method print (line 4065) | func (el *ExprList) print(ps *printState) {
method Traverse (line 4069) | func (el *ExprList) Traverse(fn func(AST) bool) {
method Copy (line 4077) | func (el *ExprList) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4102) | func (el *ExprList) GoString() string {
method goString (line 4106) | func (el *ExprList) goString(indent int, field string) string {
method prec (line 4118) | func (el *ExprList) prec() precedence {
type InitializerList (line 4124) | type InitializerList struct
method print (line 4129) | func (il *InitializerList) print(ps *printState) {
method printAsString (line 4150) | func (il *InitializerList) printAsString(ps *printState) bool {
method Traverse (line 4229) | func (il *InitializerList) Traverse(fn func(AST) bool) {
method Copy (line 4238) | func (il *InitializerList) Copy(fn func(AST) AST, skip func(AST) bool)...
method GoString (line 4263) | func (il *InitializerList) GoString() string {
method goString (line 4267) | func (il *InitializerList) goString(indent int, field string) string {
type DefaultArg (line 4279) | type DefaultArg struct
method print (line 4284) | func (da *DefaultArg) print(ps *printState) {
method Traverse (line 4291) | func (da *DefaultArg) Traverse(fn func(AST) bool) {
method Copy (line 4297) | func (da *DefaultArg) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4312) | func (da *DefaultArg) GoString() string {
method goString (line 4316) | func (da *DefaultArg) goString(indent int, field string) string {
type Closure (line 4322) | type Closure struct
method print (line 4330) | func (cl *Closure) print(ps *printState) {
method printTypes (line 4346) | func (cl *Closure) printTypes(ps *printState) {
method Traverse (line 4374) | func (cl *Closure) Traverse(fn func(AST) bool) {
method Copy (line 4391) | func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4455) | func (cl *Closure) GoString() string {
method goString (line 4459) | func (cl *Closure) goString(indent int, field string) string {
type StructuredBindings (line 4498) | type StructuredBindings struct
method print (line 4502) | func (sb *StructuredBindings) print(ps *printState) {
method Traverse (line 4508) | func (sb *StructuredBindings) Traverse(fn func(AST) bool) {
method Copy (line 4516) | func (sb *StructuredBindings) Copy(fn func(AST) AST, skip func(AST) bo...
method GoString (line 4541) | func (sb *StructuredBindings) GoString() string {
method goString (line 4545) | func (sb *StructuredBindings) goString(indent int, field string) string {
type UnnamedType (line 4556) | type UnnamedType struct
method print (line 4560) | func (ut *UnnamedType) print(ps *printState) {
method Traverse (line 4572) | func (ut *UnnamedType) Traverse(fn func(AST) bool) {
method Copy (line 4576) | func (ut *UnnamedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4583) | func (ut *UnnamedType) GoString() string {
method goString (line 4587) | func (ut *UnnamedType) goString(indent int, field string) string {
type UnnamedEnum (line 4592) | type UnnamedEnum struct
method print (line 4597) | func (ue *UnnamedEnum) print(ps *printState) {
method Traverse (line 4605) | func (ue *UnnamedEnum) Traverse(fn func(AST) bool) {
method Copy (line 4612) | func (ue *UnnamedEnum) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4634) | func (ue *UnnamedEnum) GoString() string {
method goString (line 4638) | func (ue *UnnamedEnum) goString(indent int, field string) string {
type Clone (line 4645) | type Clone struct
method print (line 4650) | func (c *Clone) print(ps *printState) {
method Traverse (line 4662) | func (c *Clone) Traverse(fn func(AST) bool) {
method Copy (line 4668) | func (c *Clone) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4683) | func (c *Clone) GoString() string {
method goString (line 4687) | func (c *Clone) goString(indent int, field string) string {
type Special (line 4694) | type Special struct
method print (line 4699) | func (s *Special) print(ps *printState) {
method Traverse (line 4713) | func (s *Special) Traverse(fn func(AST) bool) {
method Copy (line 4719) | func (s *Special) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4734) | func (s *Special) GoString() string {
method goString (line 4738) | func (s *Special) goString(indent int, field string) string {
type Special2 (line 4744) | type Special2 struct
method print (line 4751) | func (s *Special2) print(ps *printState) {
method Traverse (line 4758) | func (s *Special2) Traverse(fn func(AST) bool) {
method Copy (line 4765) | func (s *Special2) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4787) | func (s *Special2) GoString() string {
method goString (line 4791) | func (s *Special2) goString(indent int, field string) string {
type EnableIf (line 4798) | type EnableIf struct
method print (line 4803) | func (ei *EnableIf) print(ps *printState) {
method Traverse (line 4810) | func (ei *EnableIf) Traverse(fn func(AST) bool) {
method Copy (line 4819) | func (ei *EnableIf) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4848) | func (ei *EnableIf) GoString() string {
method goString (line 4852) | func (ei *EnableIf) goString(indent int, field string) string {
type ModuleName (line 4868) | type ModuleName struct
method print (line 4874) | func (mn *ModuleName) print(ps *printState) {
method Traverse (line 4886) | func (mn *ModuleName) Traverse(fn func(AST) bool) {
method Copy (line 4895) | func (mn *ModuleName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4920) | func (mn *ModuleName) GoString() string {
method goString (line 4924) | func (mn *ModuleName) goString(indent int, field string) string {
type ModuleEntity (line 4937) | type ModuleEntity struct
method print (line 4942) | func (me *ModuleEntity) print(ps *printState) {
method Traverse (line 4948) | func (me *ModuleEntity) Traverse(fn func(AST) bool) {
method Copy (line 4955) | func (me *ModuleEntity) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 4977) | func (me *ModuleEntity) GoString() string {
method goString (line 4981) | func (me *ModuleEntity) goString(indent int, field string) string {
type Friend (line 4988) | type Friend struct
method print (line 4992) | func (f *Friend) print(ps *printState) {
method Traverse (line 5002) | func (f *Friend) Traverse(fn func(AST) bool) {
method Copy (line 5008) | func (f *Friend) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 5023) | func (f *Friend) GoString() string {
method goString (line 5027) | func (f *Friend) goString(indent int, field string) string {
type Constraint (line 5036) | type Constraint struct
method print (line 5042) | func (c *Constraint) print(ps *printState) {
method Traverse (line 5054) | func (c *Constraint) Traverse(fn func(AST) bool) {
method Copy (line 5061) | func (c *Constraint) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 5087) | func (c *Constraint) GoString() string {
method goString (line 5091) | func (c *Constraint) goString(indent int, field string) string {
type RequiresExpr (line 5099) | type RequiresExpr struct
method print (line 5104) | func (re *RequiresExpr) print(ps *printState) {
method Traverse (line 5121) | func (re *RequiresExpr) Traverse(fn func(AST) bool) {
method Copy (line 5132) | func (re *RequiresExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
method GoString (line 5175) | func (re *RequiresExpr) GoString() string {
method goString (line 5179) | func (re *RequiresExpr) goString(indent int, field string) string {
type ExprRequirement (line 5204) | type ExprRequirement struct
method print (line 5210) | func (er *ExprRequirement) print(ps *printState) {
method Traverse (line 5229) | func (er *ExprRequirement) Traverse(fn func(AST) bool) {
method Copy (line 5238) | func (er *ExprRequirement) Copy(fn func(AST) AST, skip func(AST) bool)...
method GoString (line 5263) | func (er *ExprRequirement) GoString() string {
method goString (line 5267) | func (er *ExprRequirement) goString(indent int, field string) string {
type TypeRequirement (line 5280) | type TypeRequirement struct
method print (line 5284) | func (tr *TypeRequirement) print(ps *printState) {
method Traverse (line 5290) | func (tr *TypeRequirement) Traverse(fn func(AST) bool) {
method Copy (line 5296) | func (tr *TypeRequirement) Copy(fn func(AST) AST, skip func(AST) bool)...
method GoString (line 5311) | func (tr *TypeRequirement) GoString() string {
method goString (line 5315) | func (tr *TypeRequirement) goString(indent int, field string) string {
type NestedRequirement (line 5321) | type NestedRequirement struct
method print (line 5325) | func (nr *NestedRequirement) print(ps *printState) {
method Traverse (line 5331) | func (nr *NestedRequirement) Traverse(fn func(AST) bool) {
method Copy (line 5337) | func (nr *NestedRequirement) Copy(fn func(AST) AST, skip func(AST) boo...
method GoString (line 5352) | func (nr *NestedRequirement) GoString() string {
method goString (line 5356) | func (nr *NestedRequirement) goString(indent int, field string) string {
type ExplicitObjectParameter (line 5362) | type ExplicitObjectParameter struct
method print (line 5366) | func (eop *ExplicitObjectParameter) print(ps *printState) {
method Traverse (line 5371) | func (eop *ExplicitObjectParameter) Traverse(fn func(AST) bool) {
method Copy (line 5377) | func (eop *ExplicitObjectParameter) Copy(fn func(AST) AST, skip func(A...
method GoString (line 5392) | func (eop *ExplicitObjectParameter) GoString() string {
method goString (line 5396) | func (eop *ExplicitObjectParameter) goString(indent int, field string)...
type innerPrinter (line 5416) | type innerPrinter interface
FILE: ast_test.go
function TestASTToString (line 12) | func TestASTToString(t *testing.T) {
FILE: c++filt.go
function flagUsage (line 25) | func flagUsage() {
function usage (line 29) | func usage(w io.Writer, status int) {
constant symbolChars (line 56) | symbolChars = "_$."
function main (line 58) | func main() {
function doDemangle (line 124) | func doDemangle(out *bufio.Writer, name string) {
function options (line 145) | func options() []demangle.Option {
FILE: cases_test.go
function TestCases (line 62) | func TestCases(t *testing.T) {
function readCases (line 157) | func readCases(t testing.TB) [][2]string {
function readCasesString (line 219) | func readCasesString(t testing.TB, r *bufio.Reader, fn string, lineno *i...
function readCasesUnquotedByte (line 303) | func readCasesUnquotedByte(t testing.TB, r *bufio.Reader, fn string, lin...
function readCasesUnquotedByteNoEOF (line 344) | func readCasesUnquotedByteNoEOF(t testing.TB, r *bufio.Reader, fn string...
function readCasesByte (line 355) | func readCasesByte(t testing.TB, r *bufio.Reader, fn string, lineno int)...
function readCasesByteNoEOF (line 368) | func readCasesByteNoEOF(t testing.TB, r *bufio.Reader, fn string, lineno...
FILE: demangle.go
type Option (line 26) | type Option
constant NoParams (line 34) | NoParams Option = iota
constant NoTemplateParams (line 38) | NoTemplateParams
constant NoEnclosingParams (line 43) | NoEnclosingParams
constant NoClones (line 47) | NoClones
constant NoRust (line 52) | NoRust
constant Verbose (line 55) | Verbose
constant LLVMStyle (line 61) | LLVMStyle
constant maxLengthShift (line 65) | maxLengthShift = 16
constant maxLengthMask (line 68) | maxLengthMask = 0x1f << maxLengthShift
function MaxLength (line 75) | func MaxLength(pow int) Option {
function isMaxLength (line 83) | func isMaxLength(opt Option) bool {
function maxLength (line 88) | func maxLength(opt Option) int {
function Filter (line 95) | func Filter(name string, options ...Option) string {
function ToString (line 107) | func ToString(name string, options ...Option) (string, error) {
function ToAST (line 152) | func ToAST(name string, options ...Option) (AST, error) {
function globalCDtorName (line 209) | func globalCDtorName(name string, options ...Option) (AST, error) {
function allocToken (line 251) | func allocToken(name string, options ...Option) (AST, error) {
function doDemangle (line 279) | func doDemangle(name string, options ...Option) (ret AST, err error) {
type state (line 333) | type state struct
method copy (line 354) | func (st *state) copy() *state {
method fail (line 361) | func (st *state) fail(err string) {
method failEarlier (line 367) | func (st *state) failEarlier(err string, dec int) {
method advance (line 375) | func (st *state) advance(add int) {
method checkChar (line 385) | func (st *state) checkChar(c byte) {
method encoding (line 429) | func (st *state) encoding(params bool, local forLocalNameType) AST {
method taggedName (line 625) | func (st *state) taggedName(a AST) AST {
method name (line 649) | func (st *state) name() (AST, bool) {
method nestedName (line 741) | func (st *state) nestedName() (AST, bool) {
method prefix (line 783) | func (st *state) prefix() AST {
method unqualifiedName (line 988) | func (st *state) unqualifiedName(module AST) (r AST, isCast bool) {
method sourceName (line 1083) | func (st *state) sourceName() AST {
method moduleName (line 1118) | func (st *state) moduleName(parent AST) AST {
method number (line 1141) | func (st *state) number() int {
method seqID (line 1171) | func (st *state) seqID(eofOK bool) int {
method operatorName (line 1304) | func (st *state) operatorName(inExpression bool) (AST, int) {
method localName (line 1344) | func (st *state) localName() (AST, bool) {
method javaResource (line 1373) | func (st *state) javaResource() AST {
method specialName (line 1432) | func (st *state) specialName() AST {
method callOffset (line 1563) | func (st *state) callOffset(c byte) {
method demangleType (line 1635) | func (st *state) demangleType(isCast bool) AST {
method demangleCastTemplateArgs (line 2060) | func (st *state) demangleCastTemplateArgs(tp AST, addSubst bool) AST {
method cvQualifiers (line 2136) | func (st *state) cvQualifiers() AST {
method refQualifier (line 2187) | func (st *state) refQualifier() string {
method parmlist (line 2204) | func (st *state) parmlist(explicitObjectParameter bool) []AST {
method functionType (line 2250) | func (st *state) functionType() AST {
method bareFunctionType (line 2271) | func (st *state) bareFunctionType(hasReturnType, explicitObjectParamet...
method arrayType (line 2292) | func (st *state) arrayType(isCast bool) AST {
method vectorType (line 2335) | func (st *state) vectorType(isCast bool) AST {
method pointerToMemberType (line 2362) | func (st *state) pointerToMemberType(isCast bool) AST {
method compactNumber (line 2390) | func (st *state) compactNumber() int {
method templateParam (line 2420) | func (st *state) templateParam() AST {
method setTemplate (line 2472) | func (st *state) setTemplate(a AST, tmpl *Template) {
method clearTemplateArgs (line 2521) | func (st *state) clearTemplateArgs(args []AST) {
method templateArgs (line 2532) | func (st *state) templateArgs() ([]AST, AST) {
method templateArg (line 2565) | func (st *state) templateArg(prev []AST) AST {
method maybeAddConstraint (line 2622) | func (st *state) maybeAddConstraint(a, constraint AST) AST {
method template (line 2634) | func (st *state) template(name AST) AST {
method exprList (line 2641) | func (st *state) exprList(stop byte) AST {
method expression (line 2720) | func (st *state) expression() AST {
method subobject (line 2979) | func (st *state) subobject() AST {
method unresolvedName (line 3019) | func (st *state) unresolvedName() AST {
method baseUnresolvedName (line 3096) | func (st *state) baseUnresolvedName() AST {
method requiresExpr (line 3130) | func (st *state) requiresExpr() AST {
method exprPrimary (line 3208) | func (st *state) exprPrimary() AST {
method discriminator (line 3279) | func (st *state) discriminator(a AST) AST {
method closureTypeName (line 3318) | func (st *state) closureTypeName() AST {
method templateParamDecl (line 3386) | func (st *state) templateParamDecl() (AST, AST) {
method unnamedTypeName (line 3493) | func (st *state) unnamedTypeName() AST {
method unnamedEnum (line 3504) | func (st *state) unnamedEnum() AST {
method constraintExpr (line 3519) | func (st *state) constraintExpr() AST {
method cloneSuffix (line 3531) | func (st *state) cloneSuffix(a AST) AST {
method substitution (line 3626) | func (st *state) substitution(forPrefix bool) AST {
method findArgumentPack (line 3917) | func (st *state) findArgumentPack(a AST) *ArgumentPack {
type demangleErr (line 394) | type demangleErr struct
method Error (line 400) | func (de demangleErr) Error() string {
function adjustErr (line 406) | func adjustErr(err error, adj int) error {
type forLocalNameType (line 417) | type forLocalNameType
constant forLocalName (line 420) | forLocalName forLocalNameType = iota
constant notForLocalName (line 421) | notForLocalName
function hasReturnType (line 589) | func hasReturnType(a AST) bool {
function isCDtorConversion (line 611) | func isCDtorConversion(a AST) bool {
type operator (line 1206) | type operator struct
function mergeQualifiers (line 2096) | func mergeQualifiers(q1AST, q2AST AST) AST {
type substitutions (line 3552) | type substitutions
method add (line 3555) | func (subs *substitutions) add(a AST) {
function isDigit (line 3786) | func isDigit(c byte) bool {
function isUpper (line 3791) | func isUpper(c byte) bool {
function isLower (line 3796) | func isLower(c byte) bool {
function simplify (line 3802) | func simplify(a AST) AST {
function simplifyOne (line 3819) | func simplifyOne(a AST) AST {
FILE: demangle_test.go
function TestDemangler (line 412) | func TestDemangler(t *testing.T) {
function TestFailure (line 600) | func TestFailure(t *testing.T) {
function TestMaxLength (line 628) | func TestMaxLength(t *testing.T) {
function TestOptionsSlice (line 644) | func TestOptionsSlice(t *testing.T) {
FILE: expected_test.go
constant filename (line 18) | filename = "testdata/demangle-expected"
function TestExpected (line 63) | func TestExpected(t *testing.T) {
function oneTest (line 103) | func oneTest(t *testing.T, report int, input, expect string, params bool) {
function getLine (line 165) | func getLine(t testing.TB, scanner *bufio.Scanner, lineno *int) string {
function getOptLine (line 175) | func getOptLine(t testing.TB, scanner *bufio.Scanner, lineno *int) (stri...
function skipExpectedTest (line 190) | func skipExpectedTest(t testing.TB, format, input string, report int) (s...
FILE: fuzz_test.go
function FuzzDemangle (line 14) | func FuzzDemangle(f *testing.F) {
function FuzzRustDemangle (line 79) | func FuzzRustDemangle(f *testing.F) {
FILE: rust.go
function rustToString (line 16) | func rustToString(name string, options []Option) (ret string, err error) {
type rustState (line 82) | type rustState struct
method fail (line 95) | func (rst *rustState) fail(err string) {
method advance (line 100) | func (rst *rustState) advance(add int) {
method checkChar (line 110) | func (rst *rustState) checkChar(c byte) {
method writeByte (line 118) | func (rst *rustState) writeByte(c byte) {
method writeString (line 131) | func (rst *rustState) writeString(s string) {
method symbolName (line 151) | func (rst *rustState) symbolName() {
method path (line 184) | func (rst *rustState) path(needsSeparator bool) {
method implPath (line 271) | func (rst *rustState) implPath() {
method identifier (line 288) | func (rst *rustState) identifier() (int64, string) {
method disambiguator (line 297) | func (rst *rustState) disambiguator() int64 {
method undisambiguatedIdentifier (line 308) | func (rst *rustState) undisambiguatedIdentifier() (id string, isPunyco...
method expandPunycode (line 348) | func (rst *rustState) expandPunycode(s string) string {
method genericArgs (line 455) | func (rst *rustState) genericArgs() {
method genericArg (line 481) | func (rst *rustState) genericArg() {
method binder (line 499) | func (rst *rustState) binder() {
method demangleType (line 537) | func (rst *rustState) demangleType() {
method basicType (line 651) | func (rst *rustState) basicType() {
method fnSig (line 668) | func (rst *rustState) fnSig() {
method dynBounds (line 713) | func (rst *rustState) dynBounds() {
method dynTrait (line 732) | func (rst *rustState) dynTrait() {
method pathStartGenerics (line 754) | func (rst *rustState) pathStartGenerics() bool {
method writeLifetime (line 777) | func (rst *rustState) writeLifetime(lifetime int64) {
method demangleConst (line 803) | func (rst *rustState) demangleConst() {
method base62Number (line 936) | func (rst *rustState) base62Number() int64 {
method backref (line 966) | func (rst *rustState) backref(demangle func()) {
method decimalNumber (line 999) | func (rst *rustState) decimalNumber() int {
function oldRustToString (line 1019) | func oldRustToString(name string, options []Option) (string, bool) {
FILE: rust_expected_test.go
constant rustFilename (line 15) | rustFilename = "testdata/rust-demangle-expected"
function TestRustExpected (line 19) | func TestRustExpected(t *testing.T) {
function oneRustTest (line 48) | func oneRustTest(t *testing.T, report int, input, expect string) {
function skipExpectedRustTest (line 81) | func skipExpectedRustTest(t testing.TB, format, input string, report int...
constant rustCheckFilename (line 98) | rustCheckFilename = "testdata/rust.test"
function TestRustCheck (line 100) | func TestRustCheck(t *testing.T) {
constant rustMangledTemplates (line 136) | rustMangledTemplates = "_RNCINvMNtNtNtNtCs5myfTy8mnaF_6timely8dataflow9o...
function TestRustNoTemplaraParams (line 138) | func TestRustNoTemplaraParams(t *testing.T) {
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,845K chars).
[
{
"path": ".gitignore",
"chars": 78,
"preview": "*.o\n*.a\n*.so\n._*\n.nfs.*\na.out\n*~\n*.orig\n*.rej\n*.exe\n.*.swp\ncore\ndemangle.test\n"
},
{
"path": "LICENSE",
"chars": 1479,
"preview": "Copyright (c) 2015 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or with"
},
{
"path": "README.md",
"chars": 107,
"preview": "# github.com/ianlancetaylor/demangle\n\nA Go package that can be used to demangle C++ and Rust symbol names.\n"
},
{
"path": "SECURITY.md",
"chars": 686,
"preview": "# Security Policy\n\n## Supported Versions\n\nSecurity updates are applied only to the latest release.\n\n## Reporting a Vulne"
},
{
"path": "ast.go",
"chars": 112903,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "ast_test.go",
"chars": 902,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "c++filt.go",
"chars": 4053,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "cases_test.go",
"chars": 11362,
"preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "demangle.go",
"chars": 102646,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "demangle_test.go",
"chars": 50930,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "expected_test.go",
"chars": 7463,
"preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "fuzz_test.go",
"chars": 2455,
"preview": "// Copyright 2025 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go.mod",
"chars": 51,
"preview": "module github.com/ianlancetaylor/demangle\n\ngo 1.13\n"
},
{
"path": "rust.go",
"chars": 23888,
"preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "rust_expected_test.go",
"chars": 4494,
"preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "testdata/DemangleTestCases.inc",
"chars": 5247050,
"preview": "// clang-format off\n{\"_Z1A\", \"A\"},\n{\"_Z1Av\", \"A()\"},\n{\"_Z1A1B1C\", \"A(B, C)\"},\n{\"_Z1fDB3_\", \"f(_BitInt(3))\"},\n{\"_Z1fDU10_"
},
{
"path": "testdata/demangle-expected",
"chars": 66919,
"preview": "# This file holds test cases for the demangler.\n# Each test case looks like this:\n# options\n# input to be demangled\n# "
},
{
"path": "testdata/rust-demangle-expected",
"chars": 10127,
"preview": "# This file holds test cases for the Rust demangler.\n# Each test case looks like this:\n# options\n# input to be demangl"
},
{
"path": "testdata/rust.test",
"chars": 9502,
"preview": "RUN: llvm-cxxfilt -n < %s | FileCheck --match-full-lines %s\n\nCHECK: a::main\n _RNvC1a4main\n\nCHECK: hello::rust\n "
}
]
About this extraction
This page contains the full source code of the ianlancetaylor/demangle GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (5.4 MB), approximately 1.4M tokens, and a symbol index with 685 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.