diff options
| author | Taras Madan <tarasmadan@google.com> | 2025-01-22 16:07:17 +0100 |
|---|---|---|
| committer | Taras Madan <tarasmadan@google.com> | 2025-01-23 10:42:36 +0000 |
| commit | 7b4377ad9d8a7205416df8d6217ef2b010f89481 (patch) | |
| tree | e6fec4fd12ff807a16d847923f501075bf71d16c /vendor/github.com/ianlancetaylor | |
| parent | 475a4c203afb8b7d3af51c4fd32bb170ff32a45e (diff) | |
vendor: delete
Diffstat (limited to 'vendor/github.com/ianlancetaylor')
| -rw-r--r-- | vendor/github.com/ianlancetaylor/demangle/.gitignore | 13 | ||||
| -rw-r--r-- | vendor/github.com/ianlancetaylor/demangle/LICENSE | 27 | ||||
| -rw-r--r-- | vendor/github.com/ianlancetaylor/demangle/README.md | 3 | ||||
| -rw-r--r-- | vendor/github.com/ianlancetaylor/demangle/SECURITY.md | 13 | ||||
| -rw-r--r-- | vendor/github.com/ianlancetaylor/demangle/ast.go | 5256 | ||||
| -rw-r--r-- | vendor/github.com/ianlancetaylor/demangle/demangle.go | 3689 | ||||
| -rw-r--r-- | vendor/github.com/ianlancetaylor/demangle/rust.go | 1165 |
7 files changed, 0 insertions, 10166 deletions
diff --git a/vendor/github.com/ianlancetaylor/demangle/.gitignore b/vendor/github.com/ianlancetaylor/demangle/.gitignore deleted file mode 100644 index 4a8b38f46..000000000 --- a/vendor/github.com/ianlancetaylor/demangle/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -*.o -*.a -*.so -._* -.nfs.* -a.out -*~ -*.orig -*.rej -*.exe -.*.swp -core -demangle.test diff --git a/vendor/github.com/ianlancetaylor/demangle/LICENSE b/vendor/github.com/ianlancetaylor/demangle/LICENSE deleted file mode 100644 index d29b37261..000000000 --- a/vendor/github.com/ianlancetaylor/demangle/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -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. diff --git a/vendor/github.com/ianlancetaylor/demangle/README.md b/vendor/github.com/ianlancetaylor/demangle/README.md deleted file mode 100644 index 2c01cae08..000000000 --- a/vendor/github.com/ianlancetaylor/demangle/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# github.com/ianlancetaylor/demangle - -A Go package that can be used to demangle C++ and Rust symbol names. diff --git a/vendor/github.com/ianlancetaylor/demangle/SECURITY.md b/vendor/github.com/ianlancetaylor/demangle/SECURITY.md deleted file mode 100644 index f4edf9e4e..000000000 --- a/vendor/github.com/ianlancetaylor/demangle/SECURITY.md +++ /dev/null @@ -1,13 +0,0 @@ -# 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. diff --git a/vendor/github.com/ianlancetaylor/demangle/ast.go b/vendor/github.com/ianlancetaylor/demangle/ast.go deleted file mode 100644 index 9e1fb0661..000000000 --- a/vendor/github.com/ianlancetaylor/demangle/ast.go +++ /dev/null @@ -1,5256 +0,0 @@ -// 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" - "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 - - 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) - 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 -} - -func (bfp *BinaryFP) print(ps *printState) { - fmt.Fprintf(&ps.buf, "_Float%d", bfp.Bits) -} - -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: %d", indent, "", field, bfp.Bits) -} - -// 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 tpn.Index > 0 { - ps.writeString(fmt.Sprintf("%d", tpn.Index-1)) - } -} - -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 { - name := tpn.Prefix - if tpn.Index > 0 { - name += fmt.Sprintf("%d", tpn.Index-1) - } - return fmt.Sprintf("%*s%sTemplateParamName: %s", indent, "", field, name) -} - -// 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 ") - ps.printInner(false) - 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 { - 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 - - ps.writeString("template<") - ps.printList(ttp.Params, nil) - ps.writeString("> typename ") - - ps.scopes = scopes - - 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} - if nttp, ok := tpp.Param.(*NonTypeTemplateParam); ok { - ps.print(nttp.Type) - } else { - ps.print(tpp.Param) - } - if len(ps.inner) > 0 { - ps.writeString("...") - } -} - -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 { - isDelete := op != nil && (op.Name == "delete " || op.Name == "delete[] ") - if op != nil && op.Name == "::" { - // Don't use parentheses after ::. - ps.print(expr) - } else if u.SizeofType { - // Always use parentheses for sizeof argument. - ps.startScope('(') - ps.print(expr) - ps.endScope(')') - } else if op != nil && op.Name == "__alignof__" { - // Always use parentheses for __alignof__ argument. - 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 isDelete: - 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 && op.Name == "()" { - if ty, ok := b.Left.(*Typed); ok { - if ft, ok := ty.Type.(*FunctionType); ok { - if ft.Return == nil { - left = ty.Name - } else { - skipParens = true - } - } else { - left = ty.Name - } - } - if ps.llvmStyle { - skipParens = true - } - } - - if skipParens { - ps.print(left) - } else if ps.llvmStyle { - prec := precPrimary - if p, ok := left.(hasPrec); ok { - prec = p.prec() - } - needsParen := false - 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 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 { - ps.print(il.Type) - } - ps.writeByte('{') - ps.print(il.Exprs) - ps.writeByte('}') -} - -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) -} - -// 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) { - 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) { - ps.writeString("friend ") - ps.print(f.Name) -} - -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. -type Constraint struct { - Name AST - Requires AST -} - -func (c *Constraint) print(ps *printState) { - ps.print(c.Name) - 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} - 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:\n%s\n%s", indent, "", field, - 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 - } -} diff --git a/vendor/github.com/ianlancetaylor/demangle/demangle.go b/vendor/github.com/ianlancetaylor/demangle/demangle.go deleted file mode 100644 index 4ca57e62a..000000000 --- a/vendor/github.com/ianlancetaylor/demangle/demangle.go +++ /dev/null @@ -1,3689 +0,0 @@ -// 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 prefix = "_GLOBAL_" - if strings.HasPrefix(name, prefix) { - // 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], options[i+1:]...) - } else { - i++ - } - } - a, err := globalCDtorName(name[len(prefix):], options...) - return a, adjustErr(err, len(prefix)) - } - - 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 - } -} - -// 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) - } - } - 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 - if strings.HasPrefix(st.str, enableIfPrefix) { - st.advance(len(enableIfPrefix) - 1) - enableIfArgs = 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 - } - } - - r := AST(&Typed{Name: a, Type: ft}) - - if len(enableIfArgs) > 0 { - r = &EnableIf{Type: r, Args: enableIfArgs} - } - - if constraint != nil { - r = &Constraint{Name: r, Requires: constraint} - } - - 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) - 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 - } - if len(st.str) > 0 && st.str[0] == 'I' { - // This can only happen if we saw - // <unscoped-template-name> and are about to see - // <template-args>. <unscoped-template-name> is a - // substitution candidate if it did not come from a - // substitution. - if !subst { - st.subs.add(a) - } - args := st.templateArgs() - tmpl := &Template{Name: a, Args: args} - if isCast { - st.setTemplate(a, tmpl) - st.clearTemplateArgs(args) - isCast = false - } - a = tmpl - } - if isCast { - st.setTemplate(a, nil) - } - return a, false - } - - a, isCast := st.unqualifiedName(module) - if len(st.str) > 0 && st.str[0] == 'I' { - st.subs.add(a) - args := st.templateArgs() - tmpl := &Template{Name: a, Args: args} - if isCast { - st.setTemplate(a, tmpl) - st.clearTemplateArgs(args) - isCast = false - } - a = tmpl - } - if isCast { - st.setTemplate(a, nil) - } - return a, 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 tn, ok := un.(*TaggedName); ok { - un = tn.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") - } - 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") - } - 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") - } - var args []AST - args = st.templateArgs() - tmpl := &Template{Name: a, Args: args} - if cast != nil { - st.setTemplate(cast, tmpl) - st.clearTemplateArgs(args) - cast = nil - } - a = nil - next = tmpl - 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) { - if len(st.str) < 1 { - st.fail("expected unqualified name") - } - - module = st.moduleName(module) - - friend := false - if len(st.str) > 0 && st.str[0] == 'F' { - st.advance(1) - friend = true - } - - 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 '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." - "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) - args := st.templateArgs() - ret = &Template{Name: ret, Args: args} - } 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 { - ret, _ = st.unqualifiedName(ret) - 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 { - args := st.templateArgs() - ret = &Template{Name: ret, Args: args} - } 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 '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' { - args := st.templateArgs() - n = &Template{Name: n, Args: args} - } - 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) - 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} - } 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} - - case 'k': - constraint, _ := st.name() - ret = &SuffixType{ - Base: constraint, - Suffix: "auto", - } - - case 'K': - constraint, _ := st.name() - ret = &SuffixType{ - Base: constraint, - Suffix: "decltype(auto)", - } - - 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 - failed := false - func() { - defer func() { - if r := recover(); r != nil { - if _, ok := r.(demangleErr); ok { - failed = true - } else { - panic(r) - } - } - }() - - args = st.templateArgs() - }() - - if !failed && len(st.str) > 0 && st.str[0] == 'I' { - if addSubst { - st.subs.add(tp) - } - return &Template{Name: tp, Args: args} - } - // 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. - 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 -func (st *state) templateArgs() []AST { - if len(st.str) == 0 || (st.str[0] != 'I' && st.str[0] != 'J') { - panic("internal error") - } - st.advance(1) - - var ret []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' { - // A list of template arguments can have a - // constraint, but we don't demangle it. - 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 -} - -// 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 := st.templateArgs() - return &ArgumentPack{Args: args} - - 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) - } -} - -// 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> -// ::= dc <type> <expression> -// ::= sc <type> <expression> -// ::= cc <type> <expression> -// ::= mc <parameter type> <expr> [<offset number>] E -// ::= rc <type> <expression> -// ::= ti <type> -// ::= te <expression> -// ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E -// ::= st <type> -// ::= sz <expression> -// ::= at <type> -// ::= az <expression> -// ::= nx <expression> -// ::= <template-param> -// ::= <function-param> -// ::= dt <expression> <unresolved-name> -// ::= pt <expression> <unresolved-name> -// ::= ds <expression> <expression> -// ::= sZ <template-param> -// ::= sZ <function-param> -// ::= sP <template-arg>* E -// ::= sp <expression> -// ::= fl <binary operator-name> <expression> -// ::= fr <binary operator-name> <expression> -// ::= fL <binary operator-name> <expression> <expression> -// ::= fR <binary operator-name> <expression> <expression> -// ::= tw <expression> -// ::= tr -// ::= u <source-name> <template-arg>* E -// ::= <unresolved-name> -// ::= <expr-primary> -// -// <function-param> ::= fp <CV-qualifiers> _ -// ::= fp <CV-qualifiers> <number> -// ::= fL <number> p <CV-qualifiers> _ -// ::= fL <number> p <CV-qualifiers> <number> -// ::= fpT -// -// <braced-expression> ::= <expression> -// ::= di <field source-name> <braced-expression> -// ::= dx <index expression> <braced-expression> -// ::= dX <range begin expression> <range end expression> <braced-expression> -func (st *state) expression() AST { - if len(st.str) == 0 { - st.fail("expected expression") - } - if st.str[0] == 'L' { - return st.exprPrimary() - } else if st.str[0] == 'T' { - return st.templateParam() - } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'o' { - st.advance(2) - return st.subobject() - } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'r' { - return st.unresolvedName() - } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'p' { - st.advance(2) - e := st.expression() - pack := st.findArgumentPack(e) - return &PackExpansion{Base: e, Pack: pack} - } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'Z' { - st.advance(2) - off := st.off - e := st.expression() - ap := st.findArgumentPack(e) - if ap == nil { - st.failEarlier("missing argument pack", st.off-off) - } - return &SizeofPack{Pack: ap} - } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'P' { - st.advance(2) - var args []AST - for len(st.str) == 0 || st.str[0] != 'E' { - arg := st.templateArg(nil) - args = append(args, arg) - } - st.advance(1) - return &SizeofArgs{Args: args} - } else if st.str[0] == 'f' && len(st.str) > 1 && st.str[1] == 'p' { - st.advance(2) - if len(st.str) > 0 && st.str[0] == 'T' { - st.advance(1) - return &FunctionParam{Index: 0} - } else { - // We can see qualifiers here, but we don't - // include them in the demangled string. - st.cvQualifiers() - index := st.compactNumber() - return &FunctionParam{Index: index + 1} - } - } else if st.str[0] == 'f' && len(st.str) > 2 && st.str[1] == 'L' && isDigit(st.str[2]) { - st.advance(2) - // We don't include the scope count in the demangled string. - st.number() - if len(st.str) == 0 || st.str[0] != 'p' { - st.fail("expected p after function parameter scope count") - } - st.advance(1) - // We can see qualifiers here, but we don't include them - // in the demangled string. - st.cvQualifiers() - index := st.compactNumber() - return &FunctionParam{Index: index + 1} - } else if st.str[0] == 'm' && len(st.str) > 1 && st.str[1] == 'c' { - st.advance(2) - typ := st.demangleType(false) - expr := st.expression() - offset := 0 - if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) { - offset = st.number() - } - if len(st.str) == 0 || st.str[0] != 'E' { - st.fail("expected E after pointer-to-member conversion") - } - st.advance(1) - return &PtrMemCast{ - Type: typ, - Expr: expr, - Offset: offset, - } - } else if isDigit(st.str[0]) || (st.str[0] == 'o' && len(st.str) > 1 && st.str[1] == 'n') { - if st.str[0] == 'o' { - // Skip operator function ID. - st.advance(2) - } - n, _ := st.unqualifiedName(nil) - if len(st.str) > 0 && st.str[0] == 'I' { - args := st.templateArgs() - n = &Template{Name: n, Args: args} - } - return n - } else if (st.str[0] == 'i' || st.str[0] == 't') && len(st.str) > 1 && st.str[1] == 'l' { - // Brace-enclosed initializer list. - c := st.str[0] - st.advance(2) - var t AST - if c == 't' { - t = st.demangleType(false) - } - exprs := st.exprList('E') - return &InitializerList{Type: t, Exprs: exprs} - } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 't' { - o, _ := st.operatorName(true) - t := st.demangleType(false) - return &Unary{Op: o, Expr: t, Suffix: false, SizeofType: true} - } else if st.str[0] == 'u' { - st.advance(1) - name := st.sourceName() - // Special case __uuidof followed by type or - // expression, as used by LLVM. - if n, ok := name.(*Name); ok && n.Name == "__uuidof" { - if len(st.str) < 2 { - st.fail("missing uuidof argument") - } - var operand AST - if st.str[0] == 't' { - st.advance(1) - operand = st.demangleType(false) - } else if st.str[0] == 'z' { - st.advance(1) - operand = st.expression() - } - if operand != nil { - return &Binary{ - Op: &Operator{Name: "()"}, - Left: name, - Right: &ExprList{ - Exprs: []AST{operand}, - }, - } - } - } - var args []AST - for { - if len(st.str) == 0 { - st.fail("missing argument in vendor extended expressoin") - } - if st.str[0] == 'E' { - st.advance(1) - break - } - arg := st.templateArg(nil) - args = append(args, arg) - } - return &Binary{ - Op: &Operator{Name: "()"}, - Left: name, - Right: &ExprList{Exprs: args}, - } - } else if st.str[0] == 'r' && len(st.str) > 1 && (st.str[1] == 'q' || st.str[1] == 'Q') { - return st.requiresExpr() - } else { - if len(st.str) < 2 { - st.fail("missing operator code") - } - code := st.str[:2] - o, args := st.operatorName(true) - switch args { - case 0: - return &Nullary{Op: o} - - case 1: - suffix := false - if code == "pp" || code == "mm" { - if len(st.str) > 0 && st.str[0] == '_' { - st.advance(1) - } else { - suffix = true - } - } - var operand AST - if _, ok := o.(*Cast); ok && len(st.str) > 0 && st.str[0] == '_' { - st.advance(1) - operand = st.exprList('E') - } else { - operand = st.expression() - } - return &Unary{Op: o, Expr: operand, Suffix: suffix, SizeofType: false} - - case 2: - var left, right AST - if code == "sc" || code == "dc" || code == "cc" || code == "rc" { - left = st.demangleType(false) - } else if code[0] == 'f' { - left, _ = st.operatorName(true) - right = st.expression() - return &Fold{Left: code[1] == 'l', Op: left, Arg1: right, Arg2: nil} - } else if code == "di" { - left, _ = st.unqualifiedName(nil) - } else { - left = st.expression() - } - if code == "cl" || code == "cp" { - right = st.exprList('E') - } else if code == "dt" || code == "pt" { - if len(st.str) > 0 && st.str[0] == 'L' { - right = st.exprPrimary() - } else { - right = st.unresolvedName() - if len(st.str) > 0 && st.str[0] == 'I' { - args := st.templateArgs() - right = &Template{Name: right, Args: args} - } - } - } else { - right = st.expression() - } - return &Binary{Op: o, Left: left, Right: right} - - case 3: - if code[0] == 'n' { - if code[1] != 'w' && code[1] != 'a' { - panic("internal error") - } - place := st.exprList('_') - if place.(*ExprList).Exprs == nil { - place = nil - } - t := st.demangleType(false) - var ini AST - if len(st.str) > 0 && st.str[0] == 'E' { - st.advance(1) - } else if len(st.str) > 1 && st.str[0] == 'p' && st.str[1] == 'i' { - // Parenthesized initializer. - st.advance(2) - ini = st.exprList('E') - } else if len(st.str) > 1 && st.str[0] == 'i' && st.str[1] == 'l' { - // Initializer list. - ini = st.expression() - } else { - st.fail("unrecognized new initializer") - } - return &New{Op: o, Place: place, Type: t, Init: ini} - } else if code[0] == 'f' { - first, _ := st.operatorName(true) - second := st.expression() - third := st.expression() - return &Fold{Left: code[1] == 'L', Op: first, Arg1: second, Arg2: third} - } else { - first := st.expression() - second := st.expression() - third := st.expression() - return &Trinary{Op: o, First: first, Second: second, Third: third} - } - - default: - st.fail(fmt.Sprintf("unsupported number of operator arguments: %d", args)) - panic("not reached") - } - } -} - -// subobject parses: -// -// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E -// <union-selector> ::= _ [<number>] -func (st *state) subobject() AST { - typ := st.demangleType(false) - expr := st.expression() - offset := 0 - if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) { - offset = st.number() - } - var selectors []int - for len(st.str) > 0 && st.str[0] == '_' { - st.advance(1) - selector := 0 - if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) { - selector = st.number() - } - selectors = append(selectors, selector) - } - pastEnd := false - if len(st.str) > 0 && st.str[0] == 'p' { - st.advance(1) - pastEnd = true - } - if len(st.str) == 0 || st.str[0] != 'E' { - st.fail("expected E after subobject") - } - st.advance(1) - return &Subobject{ - Type: typ, - SubExpr: expr, - Offset: offset, - Selectors: selectors, - PastEnd: pastEnd, - } -} - -// unresolvedName parses: -// -// <unresolved-name> ::= [gs] <base-unresolved-name> -// ::= sr <unresolved-type> <base-unresolved-name> -// ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> -// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> -func (st *state) unresolvedName() AST { - if len(st.str) >= 2 && st.str[:2] == "gs" { - st.advance(2) - n := st.unresolvedName() - return &Unary{ - Op: &Operator{Name: "::"}, - Expr: n, - Suffix: false, - SizeofType: false, - } - } else if len(st.str) >= 2 && st.str[:2] == "sr" { - st.advance(2) - if len(st.str) == 0 { - st.fail("expected unresolved type") - } - switch st.str[0] { - case 'T', 'D', 'S': - t := st.demangleType(false) - n := st.baseUnresolvedName() - n = &Qualified{Scope: t, Name: n, LocalName: false} - if len(st.str) > 0 && st.str[0] == 'I' { - args := st.templateArgs() - n = &Template{Name: n, Args: args} - st.subs.add(n) - } - return n - default: - var s AST - if st.str[0] == 'N' { - st.advance(1) - s = st.demangleType(false) - } - for len(st.str) == 0 || st.str[0] != 'E' { - // GCC does not seem to follow the ABI here. - // It can emit type/name without an 'E'. - if s != nil && len(st.str) > 0 && !isDigit(st.str[0]) { - if q, ok := s.(*Qualified); ok { - a := q.Scope - if t, ok := a.(*Template); ok { - st.subs.add(t.Name) - st.subs.add(t) - } else { - st.subs.add(a) - } - return s - } - } - n := st.sourceName() - if len(st.str) > 0 && st.str[0] == 'I' { - st.subs.add(n) - args := st.templateArgs() - n = &Template{Name: n, Args: args} - } - if s == nil { - s = n - } else { - s = &Qualified{Scope: s, Name: n, LocalName: false} - } - } - if s == nil { - st.fail("missing scope in unresolved name") - } - st.advance(1) - n := st.baseUnresolvedName() - return &Qualified{Scope: s, Name: n, LocalName: false} - } - } else { - return st.baseUnresolvedName() - } -} - -// baseUnresolvedName parses: -// -// <base-unresolved-name> ::= <simple-id> -// ::= on <operator-name> -// ::= on <operator-name> <template-args> -// ::= dn <destructor-name> -// -// <simple-id> ::= <source-name> [ <template-args> ] -func (st *state) baseUnresolvedName() AST { - var n AST - if len(st.str) >= 2 && st.str[:2] == "on" { - st.advance(2) - n, _ = st.operatorName(true) - } else if len(st.str) >= 2 && st.str[:2] == "dn" { - st.advance(2) - if len(st.str) > 0 && isDigit(st.str[0]) { - n = st.sourceName() - } else { - n = st.demangleType(false) - } - n = &Destructor{Name: n} - } else if len(st.str) > 0 && isDigit(st.str[0]) { - n = st.sourceName() - } else { - // GCC seems to not follow the ABI here: it can have - // an operator name without on. - // See https://gcc.gnu.org/PR70182. - n, _ = st.operatorName(true) - } - if len(st.str) > 0 && st.str[0] == 'I' { - args := st.templateArgs() - n = &Template{Name: n, Args: args} - } - return n -} - -// requiresExpr parses: -// -// <expression> ::= rQ <bare-function-type> _ <requirement>+ E -// ::= rq <requirement>+ E -// <requirement> ::= X <expression> [N] [R <type-constraint>] -// ::= T <type> -// ::= Q <constraint-expression> -func (st *state) requiresExpr() AST { - st.checkChar('r') - if len(st.str) == 0 || (st.str[0] != 'q' && st.str[0] != 'Q') { - st.fail("expected q or Q in requires clause in expression") - } - kind := st.str[0] - st.advance(1) - - var params []AST - if kind == 'Q' { - for len(st.str) > 0 && st.str[0] != '_' { - typ := st.demangleType(false) - params = append(params, typ) - } - st.advance(1) - } - - var requirements []AST - for len(st.str) > 0 && st.str[0] != 'E' { - var req AST - switch st.str[0] { - case 'X': - st.advance(1) - expr := st.expression() - var noexcept bool - if len(st.str) > 0 && st.str[0] == 'N' { - st.advance(1) - noexcept = true - } - var typeReq AST - if len(st.str) > 0 && st.str[0] == 'R' { - st.advance(1) - typeReq, _ = st.name() - } - req = &ExprRequirement{ - Expr: expr, - Noexcept: noexcept, - TypeReq: typeReq, - } - - case 'T': - st.advance(1) - typ := st.demangleType(false) - req = &TypeRequirement{Type: typ} - - case 'Q': - st.advance(1) - // We parse a regular expression rather than a - // constraint expression. - expr := st.expression() - req = &NestedRequirement{Constraint: expr} - - default: - st.fail("unrecognized requirement code") - } - - requirements = append(requirements, req) - } - - if len(st.str) == 0 || st.str[0] != 'E' { - st.fail("expected E after requirements") - } - st.advance(1) - - return &RequiresExpr{ - Params: params, - Requirements: requirements, - } -} - -// exprPrimary parses: -// -// <expr-primary> ::= L <type> <(value) number> E -// ::= L <type> <(value) float> E -// ::= L <mangled-name> E -func (st *state) exprPrimary() AST { - st.checkChar('L') - if len(st.str) == 0 { - st.fail("expected primary expression") - - } - - // Check for 'Z' here because g++ incorrectly omitted the - // underscore until -fabi-version=3. - var ret AST - if st.str[0] == '_' || st.str[0] == 'Z' { - if st.str[0] == '_' { - st.advance(1) - } - if len(st.str) == 0 || st.str[0] != 'Z' { - st.fail("expected mangled name") - } - st.advance(1) - ret = st.encoding(true, notForLocalName) - } else { - t := st.demangleType(false) - - isArrayType := func(typ AST) bool { - if twq, ok := typ.(*TypeWithQualifiers); ok { - typ = twq.Base - } - _, ok := typ.(*ArrayType) - return ok - } - - neg := false - if len(st.str) > 0 && st.str[0] == 'n' { - neg = true - st.advance(1) - } - if len(st.str) > 0 && st.str[0] == 'E' { - if bt, ok := t.(*BuiltinType); ok && bt.Name == "decltype(nullptr)" { - // A nullptr should not have a value. - // We accept one if present because GCC - // used to generate one. - // https://gcc.gnu.org/PR91979. - } else if cl, ok := t.(*Closure); ok { - // A closure doesn't have a value. - st.advance(1) - return &LambdaExpr{Type: cl} - } else if isArrayType(t) { - st.advance(1) - return &StringLiteral{Type: t} - } else { - st.fail("missing literal value") - } - } - i := 0 - for len(st.str) > i && st.str[i] != 'E' { - i++ - } - val := st.str[:i] - st.advance(i) - ret = &Literal{Type: t, Val: val, Neg: neg} - } - if len(st.str) == 0 || st.str[0] != 'E' { - st.fail("expected E after literal") - } - st.advance(1) - return ret -} - -// discriminator parses: -// -// <discriminator> ::= _ <(non-negative) number> (when number < 10) -// __ <(non-negative) number> _ (when number >= 10) -func (st *state) discriminator(a AST) AST { - if len(st.str) == 0 || st.str[0] != '_' { - // clang can generate a discriminator at the end of - // the string with no underscore. - for i := 0; i < len(st.str); i++ { - if !isDigit(st.str[i]) { - return a - } - } - // Skip the trailing digits. - st.advance(len(st.str)) - return a - } - off := st.off - st.advance(1) - trailingUnderscore := false - if len(st.str) > 0 && st.str[0] == '_' { - st.advance(1) - trailingUnderscore = true - } - d := st.number() - if d < 0 { - st.failEarlier("invalid negative discriminator", st.off-off) - } - if trailingUnderscore && d >= 10 { - if len(st.str) == 0 || st.str[0] != '_' { - st.fail("expected _ after discriminator >= 10") - } - st.advance(1) - } - // We don't currently print out the discriminator, so we don't - // save it. - return a -} - -// closureTypeName parses: -// -// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ -// <lambda-sig> ::= <parameter type>+ -func (st *state) closureTypeName() AST { - st.checkChar('U') - st.checkChar('l') - - oldLambdaTemplateLevel := st.lambdaTemplateLevel - st.lambdaTemplateLevel = len(st.templates) + 1 - - var templateArgs []AST - var template *Template - for len(st.str) > 1 && st.str[0] == 'T' { - arg, templateVal := st.templateParamDecl() - if arg == nil { - break - } - templateArgs = append(templateArgs, arg) - if template == nil { - template = &Template{ - Name: &Name{Name: "lambda"}, - } - st.templates = append(st.templates, template) - } - template.Args = append(template.Args, templateVal) - } - - var templateArgsConstraint AST - if len(st.str) > 0 && st.str[0] == 'Q' { - templateArgsConstraint = st.constraintExpr() - } - - types := st.parmlist(false) - - st.lambdaTemplateLevel = oldLambdaTemplateLevel - - if template != nil { - st.templates = st.templates[:len(st.templates)-1] - } - - var callConstraint AST - if len(st.str) > 0 && st.str[0] == 'Q' { - callConstraint = st.constraintExpr() - } - - if len(st.str) == 0 || st.str[0] != 'E' { - st.fail("expected E after closure type name") - } - st.advance(1) - num := st.compactNumber() - return &Closure{ - TemplateArgs: templateArgs, - TemplateArgsConstraint: templateArgsConstraint, - Types: types, - Num: num, - CallConstraint: callConstraint, - } -} - -// templateParamDecl parses: -// -// <template-param-decl> ::= Ty # type parameter -// ::= Tn <type> # non-type parameter -// ::= Tt <template-param-decl>* E # template parameter -// ::= Tp <template-param-decl> # parameter pack -// -// Returns the new AST to include in the AST we are building and the -// new AST to add to the list of template parameters. -// -// Returns nil, nil if not looking at a template-param-decl. -func (st *state) templateParamDecl() (AST, AST) { - if len(st.str) < 2 || st.str[0] != 'T' { - return nil, nil - } - mk := func(prefix string, p *int) AST { - idx := *p - (*p)++ - return &TemplateParamName{ - Prefix: prefix, - Index: idx, - } - } - switch st.str[1] { - case 'y': - st.advance(2) - name := mk("$T", &st.typeTemplateParamCount) - tp := &TypeTemplateParam{ - Name: name, - } - return tp, name - case 'k': - st.advance(2) - constraint, _ := st.name() - name := mk("$T", &st.typeTemplateParamCount) - tp := &ConstrainedTypeTemplateParam{ - Name: name, - Constraint: constraint, - } - return tp, name - case 'n': - st.advance(2) - name := mk("$N", &st.nonTypeTemplateParamCount) - typ := st.demangleType(false) - tp := &NonTypeTemplateParam{ - Name: name, - Type: typ, - } - return tp, name - case 't': - st.advance(2) - name := mk("$TT", &st.templateTemplateParamCount) - var params []AST - var template *Template - var constraint AST - for { - if len(st.str) == 0 { - st.fail("expected closure template parameter") - } - if st.str[0] == 'E' { - st.advance(1) - break - } - off := st.off - param, templateVal := st.templateParamDecl() - if param == nil { - st.failEarlier("expected closure template parameter", st.off-off) - } - params = append(params, param) - if template == nil { - template = &Template{ - Name: &Name{Name: "template_template"}, - } - st.templates = append(st.templates, template) - } - template.Args = append(template.Args, templateVal) - - if len(st.str) > 0 && st.str[0] == 'Q' { - // A list of template template - // parameters can have a constraint. - constraint = st.constraintExpr() - if len(st.str) == 0 || st.str[0] != 'E' { - st.fail("expected end of template template parameters after constraint") - } - } - } - if template != nil { - st.templates = st.templates[:len(st.templates)-1] - } - tp := &TemplateTemplateParam{ - Name: name, - Params: params, - Constraint: constraint, - } - return tp, name - case 'p': - st.advance(2) - off := st.off - param, templateVal := st.templateParamDecl() - if param == nil { - st.failEarlier("expected lambda template parameter", st.off-off) - } - return &TemplateParamPack{Param: param}, templateVal - default: - return nil, nil - } -} - -// unnamedTypeName parses: -// -// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ -func (st *state) unnamedTypeName() AST { - st.checkChar('U') - st.checkChar('t') - num := st.compactNumber() - ret := &UnnamedType{Num: num} - st.subs.add(ret) - return ret -} - -// constraintExpr parses a constraint expression. This is just a -// regular expression, but template parameters are handled specially. -func (st *state) constraintExpr() AST { - st.checkChar('Q') - - hold := st.parsingConstraint - st.parsingConstraint = true - defer func() { st.parsingConstraint = hold }() - - return st.expression() -} - -// Recognize a clone suffix. These are not part of the mangling API, -// but are added by GCC when cloning functions. -func (st *state) cloneSuffix(a AST) AST { - i := 0 - if len(st.str) > 1 && st.str[0] == '.' && (isLower(st.str[1]) || isDigit(st.str[1]) || st.str[1] == '_') { - i += 2 - for len(st.str) > i && (isLower(st.str[i]) || isDigit(st.str[i]) || st.str[i] == '_') { - i++ - } - } - for len(st.str) > i+1 && st.str[i] == '.' && isDigit(st.str[i+1]) { - i += 2 - for len(st.str) > i && isDigit(st.str[i]) { - i++ - } - } - suffix := st.str[:i] - st.advance(i) - return &Clone{Base: a, Suffix: suffix} -} - -// substitutions is the list of substitution candidates that may -// appear later in the string. -type substitutions []AST - -// add adds a new substitution candidate. -func (subs *substitutions) add(a AST) { - *subs = append(*subs, a) -} - -// subAST maps standard substitution codes to the corresponding AST. -var subAST = map[byte]AST{ - 't': &Name{Name: "std"}, - 'a': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}}, - 'b': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}}, - 's': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "string"}}, - 'i': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "istream"}}, - 'o': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "ostream"}}, - 'd': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "iostream"}}, -} - -// verboseAST maps standard substitution codes to the long form of the -// corresponding AST. We use this when the Verbose option is used, to -// match the standard demangler. -var verboseAST = map[byte]AST{ - 't': &Name{Name: "std"}, - 'a': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}}, - 'b': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}}, - - // std::basic_string<char, std::char_traits<char>, std::allocator<char> > - 's': &Template{ - Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}}, - Args: []AST{ - &BuiltinType{Name: "char"}, - &Template{ - Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}}, - Args: []AST{&BuiltinType{Name: "char"}}}, - &Template{ - Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}}, - Args: []AST{&BuiltinType{Name: "char"}}}}}, - // std::basic_istream<char, std::char_traits<char> > - 'i': &Template{ - Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_istream"}}, - Args: []AST{ - &BuiltinType{Name: "char"}, - &Template{ - Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}}, - Args: []AST{&BuiltinType{Name: "char"}}}}}, - // std::basic_ostream<char, std::char_traits<char> > - 'o': &Template{ - Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_ostream"}}, - Args: []AST{ - &BuiltinType{Name: "char"}, - &Template{ - Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}}, - Args: []AST{&BuiltinType{Name: "char"}}}}}, - // std::basic_iostream<char, std::char_traits<char> > - 'd': &Template{ - Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_iostream"}}, - Args: []AST{ - &BuiltinType{Name: "char"}, - &Template{ - Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}}, - Args: []AST{&BuiltinType{Name: "char"}}}}}, -} - -// substitution parses: -// -// <substitution> ::= S <seq-id> _ -// ::= S_ -// ::= St -// ::= Sa -// ::= Sb -// ::= Ss -// ::= Si -// ::= So -// ::= Sd -func (st *state) substitution(forPrefix bool) AST { - st.checkChar('S') - if len(st.str) == 0 { - st.fail("missing substitution index") - } - c := st.str[0] - off := st.off - if c == '_' || isDigit(c) || isUpper(c) { - id := st.seqID(false) - if id >= len(st.subs) { - st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), st.off-off) - } - - ret := st.subs[id] - - // We need to update any references to template - // parameters to refer to the currently active - // template. - - // When copying a Typed we may need to adjust - // the templates. - copyTemplates := st.templates - var oldLambdaTemplateLevel []int - - // pushTemplate is called from skip, popTemplate from copy. - pushTemplate := func(template *Template) { - copyTemplates = append(copyTemplates, template) - oldLambdaTemplateLevel = append(oldLambdaTemplateLevel, st.lambdaTemplateLevel) - st.lambdaTemplateLevel = 0 - } - popTemplate := func() { - copyTemplates = copyTemplates[:len(copyTemplates)-1] - st.lambdaTemplateLevel = oldLambdaTemplateLevel[len(oldLambdaTemplateLevel)-1] - oldLambdaTemplateLevel = oldLambdaTemplateLevel[:len(oldLambdaTemplateLevel)-1] - } - - copy := func(a AST) AST { - var index int - switch a := a.(type) { - case *Typed: - // Remove the template added in skip. - if _, ok := a.Name.(*Template); ok { - popTemplate() - } - return nil - case *Closure: - // Undo the save in skip. - st.lambdaTemplateLevel = oldLambdaTemplateLevel[len(oldLambdaTemplateLevel)-1] - oldLambdaTemplateLevel = oldLambdaTemplateLevel[:len(oldLambdaTemplateLevel)-1] - return nil - case *TemplateParam: - index = a.Index - case *LambdaAuto: - // A lambda auto parameter is represented - // as a template parameter, so we may have - // to change back when substituting. - index = a.Index - default: - return nil - } - if st.parsingConstraint { - // We don't try to substitute template - // parameters in a constraint expression. - return &Name{Name: fmt.Sprintf("T%d", index)} - } - if st.lambdaTemplateLevel > 0 { - if _, ok := a.(*LambdaAuto); ok { - return nil - } - return &LambdaAuto{Index: index} - } - var template *Template - if len(copyTemplates) > 0 { - template = copyTemplates[len(copyTemplates)-1] - } else if rt, ok := ret.(*Template); ok { - // At least with clang we can see a template - // to start, and sometimes we need to refer - // to it. There is probably something wrong - // here. - template = rt - } else { - st.failEarlier("substituted template parameter not in scope of template", st.off-off) - } - if template == nil { - // This template parameter is within - // the scope of a cast operator. - return &TemplateParam{Index: index, Template: nil} - } - - if index >= len(template.Args) { - st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", index, len(template.Args)), st.off-off) - } - - return &TemplateParam{Index: index, Template: template} - } - seen := make(map[AST]bool) - skip := func(a AST) bool { - switch a := a.(type) { - case *Typed: - if template, ok := a.Name.(*Template); ok { - // This template is removed in copy. - pushTemplate(template) - } - return false - case *Closure: - // This is undone in copy. - oldLambdaTemplateLevel = append(oldLambdaTemplateLevel, st.lambdaTemplateLevel) - st.lambdaTemplateLevel = len(copyTemplates) + 1 - return false - case *TemplateParam, *LambdaAuto: - return false - } - if seen[a] { - return true - } - seen[a] = true - return false - } - - if c := ret.Copy(copy, skip); c != nil { - return c - } - - return ret - } else { - st.advance(1) - m := subAST - if st.verbose { - m = verboseAST - } - // For compatibility with the standard demangler, use - // a longer name for a constructor or destructor. - if forPrefix && len(st.str) > 0 && (st.str[0] == 'C' || st.str[0] == 'D') { - m = verboseAST - } - a, ok := m[c] - if !ok { - st.failEarlier("unrecognized substitution code", 1) - } - - if len(st.str) > 0 && st.str[0] == 'B' { - a = st.taggedName(a) - st.subs.add(a) - } - - return a - } -} - -// isDigit returns whetner c is a digit for demangling purposes. -func isDigit(c byte) bool { - return c >= '0' && c <= '9' -} - -// isUpper returns whether c is an upper case letter for demangling purposes. -func isUpper(c byte) bool { - return c >= 'A' && c <= 'Z' -} - -// isLower returns whether c is a lower case letter for demangling purposes. -func isLower(c byte) bool { - return c >= 'a' && c <= 'z' -} - -// simplify replaces template parameters with their expansions, and -// merges qualifiers. -func simplify(a AST) AST { - seen := make(map[AST]bool) - skip := func(a AST) bool { - if seen[a] { - return true - } - seen[a] = true - return false - } - if r := a.Copy(simplifyOne, skip); r != nil { - return r - } - return a -} - -// simplifyOne simplifies a single AST. It returns nil if there is -// nothing to do. -func simplifyOne(a AST) AST { - switch a := a.(type) { - case *TemplateParam: - if a.Template != nil && a.Index < len(a.Template.Args) { - return a.Template.Args[a.Index] - } - case *MethodWithQualifiers: - if m, ok := a.Method.(*MethodWithQualifiers); ok { - ref := a.RefQualifier - if ref == "" { - ref = m.RefQualifier - } else if m.RefQualifier != "" { - if ref == "&" || m.RefQualifier == "&" { - ref = "&" - } - } - return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: ref} - } - if t, ok := a.Method.(*TypeWithQualifiers); ok { - return &MethodWithQualifiers{Method: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers), RefQualifier: a.RefQualifier} - } - case *TypeWithQualifiers: - if ft, ok := a.Base.(*FunctionType); ok { - return &MethodWithQualifiers{Method: ft, Qualifiers: a.Qualifiers, RefQualifier: ""} - } - if t, ok := a.Base.(*TypeWithQualifiers); ok { - return &TypeWithQualifiers{Base: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers)} - } - if m, ok := a.Base.(*MethodWithQualifiers); ok { - return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: m.RefQualifier} - } - case *ReferenceType: - if rt, ok := a.Base.(*ReferenceType); ok { - return rt - } - if rrt, ok := a.Base.(*RvalueReferenceType); ok { - return &ReferenceType{Base: rrt.Base} - } - case *RvalueReferenceType: - if rrt, ok := a.Base.(*RvalueReferenceType); ok { - return rrt - } - if rt, ok := a.Base.(*ReferenceType); ok { - return rt - } - case *ArrayType: - // Qualifiers on the element of an array type - // go on the whole array type. - if q, ok := a.Element.(*TypeWithQualifiers); ok { - return &TypeWithQualifiers{ - Base: &ArrayType{Dimension: a.Dimension, Element: q.Base}, - Qualifiers: q.Qualifiers, - } - } - case *PackExpansion: - // Expand the pack and replace it with a list of - // expressions. - if a.Pack != nil { - exprs := make([]AST, len(a.Pack.Args)) - for i, arg := range a.Pack.Args { - copy := func(sub AST) AST { - // Replace the ArgumentPack - // with a specific argument. - if sub == a.Pack { - return arg - } - // Copy everything else. - return nil - } - - seen := make(map[AST]bool) - skip := func(sub AST) bool { - // Don't traverse into another - // pack expansion. - if _, ok := sub.(*PackExpansion); ok { - return true - } - if seen[sub] { - return true - } - seen[sub] = true - return false - } - - b := a.Base.Copy(copy, skip) - if b == nil { - b = a.Base - } - exprs[i] = simplify(b) - } - return &ExprList{Exprs: exprs} - } - } - return nil -} - -// findArgumentPack walks the AST looking for the argument pack for a -// pack expansion. We find it via a template parameter. -func (st *state) findArgumentPack(a AST) *ArgumentPack { - seen := make(map[AST]bool) - var ret *ArgumentPack - a.Traverse(func(a AST) bool { - if ret != nil { - return false - } - switch a := a.(type) { - case *TemplateParam: - if a.Template == nil || a.Index >= len(a.Template.Args) { - return true - } - if pack, ok := a.Template.Args[a.Index].(*ArgumentPack); ok { - ret = pack - return false - } - case *PackExpansion, *Closure, *Name: - return false - case *TaggedName, *Operator, *BuiltinType, *FunctionParam: - return false - case *UnnamedType, *FixedType, *DefaultArg: - return false - } - if seen[a] { - return false - } - seen[a] = true - return true - }) - return ret -} diff --git a/vendor/github.com/ianlancetaylor/demangle/rust.go b/vendor/github.com/ianlancetaylor/demangle/rust.go deleted file mode 100644 index f3d2d33bd..000000000 --- a/vendor/github.com/ianlancetaylor/demangle/rust.go +++ /dev/null @@ -1,1165 +0,0 @@ -// 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 ( - "fmt" - "math" - "math/bits" - "strings" - "unicode/utf8" -) - -// rustToString demangles a Rust symbol. -func rustToString(name string, options []Option) (ret string, err error) { - if !strings.HasPrefix(name, "_R") { - return "", ErrNotMangledName - } - - // 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 = "" - err = de - return - } - panic(r) - } - }() - - suffix := "" - dot := strings.Index(name, ".") - if dot >= 0 { - suffix = name[dot:] - name = name[:dot] - } - - name = name[2:] - rst := &rustState{orig: name, str: name} - - for _, o := range options { - if o == NoTemplateParams { - rst.noGenericArgs = true - } else if isMaxLength(o) { - rst.max = maxLength(o) - } - } - - rst.symbolName() - - if len(rst.str) > 0 { - rst.fail("unparsed characters at end of mangled name") - } - - if suffix != "" { - llvmStyle := false - for _, o := range options { - if o == LLVMStyle { - llvmStyle = true - break - } - } - if llvmStyle { - rst.skip = false - rst.writeString(" (") - rst.writeString(suffix) - rst.writeByte(')') - } - } - - s := rst.buf.String() - if rst.max > 0 && len(s) > rst.max { - s = s[:rst.max] - } - return s, nil -} - -// A rustState holds the current state of demangling a Rust string. -type rustState struct { - orig string // the original string being demangled - str string // remainder of string to demangle - off int // offset of str within original string - buf strings.Builder // demangled string being built - skip bool // don't print, just skip - lifetimes int64 // number of bound lifetimes - last byte // last byte written to buffer - noGenericArgs bool // don't demangle generic arguments - max int // maximum output length -} - -// fail panics with demangleErr, to be caught in rustToString. -func (rst *rustState) fail(err string) { - panic(demangleErr{err: err, off: rst.off}) -} - -// advance advances the current string offset. -func (rst *rustState) advance(add int) { - if len(rst.str) < add { - panic("internal error") - } - rst.str = rst.str[add:] - rst.off += add -} - -// checkChar requires that the next character in the string be c, -// and advances past it. -func (rst *rustState) checkChar(c byte) { - if len(rst.str) == 0 || rst.str[0] != c { - rst.fail("expected " + string(c)) - } - rst.advance(1) -} - -// writeByte writes a byte to the buffer. -func (rst *rustState) writeByte(c byte) { - if rst.skip { - return - } - if rst.max > 0 && rst.buf.Len() > rst.max { - rst.skip = true - return - } - rst.last = c - rst.buf.WriteByte(c) -} - -// writeString writes a string to the buffer. -func (rst *rustState) writeString(s string) { - if rst.skip { - return - } - if rst.max > 0 && rst.buf.Len() > rst.max { - rst.skip = true - return - } - if len(s) > 0 { - rst.last = s[len(s)-1] - rst.buf.WriteString(s) - } -} - -// symbolName parses: -// -// <symbol-name> = "_R" [<decimal-number>] <path> [<instantiating-crate>] -// <instantiating-crate> = <path> -// -// We've already skipped the "_R". -func (rst *rustState) symbolName() { - if len(rst.str) < 1 { - rst.fail("expected symbol-name") - } - - if isDigit(rst.str[0]) { - rst.fail("unsupported Rust encoding version") - } - - rst.path(true) - - if len(rst.str) > 0 { - rst.skip = true - rst.path(false) - } -} - -// path parses: -// -// <path> = "C" <identifier> // crate root -// | "M" <impl-path> <type> // <T> (inherent impl) -// | "X" <impl-path> <type> <path> // <T as Trait> (trait impl) -// | "Y" <type> <path> // <T as Trait> (trait definition) -// | "N" <namespace> <path> <identifier> // ...::ident (nested path) -// | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args) -// | <backref> -// <namespace> = "C" // closure -// | "S" // shim -// | <A-Z> // other special namespaces -// | <a-z> // internal namespaces -// -// needsSeparator is true if we need to write out :: for a generic; -// it is passed as false if we are in the middle of a type. -func (rst *rustState) path(needsSeparator bool) { - if len(rst.str) < 1 { - rst.fail("expected path") - } - switch c := rst.str[0]; c { - case 'C': - rst.advance(1) - _, ident := rst.identifier() - rst.writeString(ident) - case 'M', 'X': - rst.advance(1) - rst.implPath() - rst.writeByte('<') - rst.demangleType() - if c == 'X' { - rst.writeString(" as ") - rst.path(false) - } - rst.writeByte('>') - case 'Y': - rst.advance(1) - rst.writeByte('<') - rst.demangleType() - rst.writeString(" as ") - rst.path(false) - rst.writeByte('>') - case 'N': - rst.advance(1) - - if len(rst.str) < 1 { - rst.fail("expected namespace") - } - ns := rst.str[0] - switch { - case ns >= 'a' && ns <= 'z': - case ns >= 'A' && ns <= 'Z': - default: - rst.fail("invalid namespace character") - } - rst.advance(1) - - rst.path(needsSeparator) - - dis, ident := rst.identifier() - - if ns >= 'A' && ns <= 'Z' { - rst.writeString("::{") - switch ns { - case 'C': - rst.writeString("closure") - case 'S': - rst.writeString("shim") - default: - rst.writeByte(ns) - } - if len(ident) > 0 { - rst.writeByte(':') - rst.writeString(ident) - } - if !rst.skip { - fmt.Fprintf(&rst.buf, "#%d}", dis) - rst.last = '}' - } - } else { - rst.writeString("::") - rst.writeString(ident) - } - case 'I': - rst.advance(1) - rst.path(needsSeparator) - if needsSeparator { - rst.writeString("::") - } - rst.writeByte('<') - rst.genericArgs() - rst.writeByte('>') - rst.checkChar('E') - case 'B': - rst.backref(func() { rst.path(needsSeparator) }) - default: - rst.fail("unrecognized letter in path") - } -} - -// implPath parses: -// -// <impl-path> = [<disambiguator>] <path> -func (rst *rustState) implPath() { - // This path is not part of the demangled string. - hold := rst.skip - rst.skip = true - defer func() { - rst.skip = hold - }() - - rst.disambiguator() - rst.path(false) -} - -// identifier parses: -// -// <identifier> = [<disambiguator>] <undisambiguated-identifier> -// -// It returns the disambiguator and the identifier. -func (rst *rustState) identifier() (int64, string) { - dis := rst.disambiguator() - ident, _ := rst.undisambiguatedIdentifier() - return dis, ident -} - -// disambiguator parses an optional: -// -// <disambiguator> = "s" <base-62-number> -func (rst *rustState) disambiguator() int64 { - if len(rst.str) == 0 || rst.str[0] != 's' { - return 0 - } - rst.advance(1) - return rst.base62Number() + 1 -} - -// undisambiguatedIdentifier parses: -// -// <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes> -func (rst *rustState) undisambiguatedIdentifier() (id string, isPunycode bool) { - isPunycode = false - if len(rst.str) > 0 && rst.str[0] == 'u' { - rst.advance(1) - isPunycode = true - } - - val := rst.decimalNumber() - - if len(rst.str) > 0 && rst.str[0] == '_' { - rst.advance(1) - } - - if len(rst.str) < val { - rst.fail("not enough characters for identifier") - } - id = rst.str[:val] - rst.advance(val) - - for i := 0; i < len(id); i++ { - c := id[i] - switch { - case c >= '0' && c <= '9': - case c >= 'A' && c <= 'Z': - case c >= 'a' && c <= 'z': - case c == '_': - default: - rst.fail("invalid character in identifier") - } - } - - if isPunycode { - id = rst.expandPunycode(id) - } - - return id, isPunycode -} - -// expandPunycode decodes the Rust version of punycode. -// This algorithm is taken from RFC 3492 section 6.2. -func (rst *rustState) expandPunycode(s string) string { - const ( - base = 36 - tmin = 1 - tmax = 26 - skew = 38 - damp = 700 - initialBias = 72 - initialN = 128 - ) - - var ( - output []rune - encoding string - ) - idx := strings.LastIndex(s, "_") - if idx >= 0 { - output = []rune(s[:idx]) - encoding = s[idx+1:] - } else { - encoding = s - } - - i := 0 - n := initialN - bias := initialBias - - pos := 0 - for pos < len(encoding) { - oldI := i - w := 1 - for k := base; ; k += base { - if pos == len(encoding) { - rst.fail("unterminated punycode") - } - - var digit byte - d := encoding[pos] - pos++ - switch { - case '0' <= d && d <= '9': - digit = d - '0' + 26 - case 'A' <= d && d <= 'Z': - digit = d - 'A' - case 'a' <= d && d <= 'z': - digit = d - 'a' - default: - rst.fail("invalid punycode digit") - } - - i += int(digit) * w - if i < 0 { - rst.fail("punycode number overflow") - } - - var t int - if k <= bias { - t = tmin - } else if k > bias+tmax { - t = tmax - } else { - t = k - bias - } - - if int(digit) < t { - break - } - - if w >= math.MaxInt32/base { - rst.fail("punycode number overflow") - } - w *= base - t - } - - delta := i - oldI - numPoints := len(output) + 1 - firstTime := oldI == 0 - if firstTime { - delta /= damp - } else { - delta /= 2 - } - delta += delta / numPoints - k := 0 - for delta > ((base-tmin)*tmax)/2 { - delta /= base - tmin - k += base - } - bias = k + ((base-tmin+1)*delta)/(delta+skew) - - n += i / (len(output) + 1) - if n > utf8.MaxRune { - rst.fail("punycode rune overflow") - } else if !utf8.ValidRune(rune(n)) { - rst.fail("punycode invalid code point") - } - i %= len(output) + 1 - output = append(output, 0) - copy(output[i+1:], output[i:]) - output[i] = rune(n) - i++ - } - - return string(output) -} - -// genericArgs prints a list of generic arguments, without angle brackets. -func (rst *rustState) genericArgs() { - if rst.noGenericArgs { - hold := rst.skip - rst.skip = true - defer func() { - rst.skip = hold - }() - } - - first := true - for len(rst.str) > 0 && rst.str[0] != 'E' { - if first { - first = false - } else { - rst.writeString(", ") - } - rst.genericArg() - } -} - -// genericArg parses: -// -// <generic-arg> = <lifetime> -// | <type> -// | "K" <const> // forward-compat for const generics -// <lifetime> = "L" <base-62-number> -func (rst *rustState) genericArg() { - if len(rst.str) < 1 { - rst.fail("expected generic-arg") - } - if rst.str[0] == 'L' { - rst.advance(1) - rst.writeLifetime(rst.base62Number()) - } else if rst.str[0] == 'K' { - rst.advance(1) - rst.demangleConst() - } else { - rst.demangleType() - } -} - -// binder parses an optional: -// -// <binder> = "G" <base-62-number> -func (rst *rustState) binder() { - if len(rst.str) < 1 || rst.str[0] != 'G' { - return - } - rst.advance(1) - - binderLifetimes := rst.base62Number() + 1 - - // Every bound lifetime should be referenced later. - if binderLifetimes >= int64(len(rst.str))-rst.lifetimes { - rst.fail("binder lifetimes overflow") - } - - rst.writeString("for<") - for i := int64(0); i < binderLifetimes; i++ { - if i > 0 { - rst.writeString(", ") - } - rst.lifetimes++ - rst.writeLifetime(1) - } - rst.writeString("> ") -} - -// demangleType parses: -// -// <type> = <basic-type> -// | <path> // named type -// | "A" <type> <const> // [T; N] -// | "S" <type> // [T] -// | "T" {<type>} "E" // (T1, T2, T3, ...) -// | "R" [<lifetime>] <type> // &T -// | "Q" [<lifetime>] <type> // &mut T -// | "P" <type> // *const T -// | "O" <type> // *mut T -// | "F" <fn-sig> // fn(...) -> ... -// | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a -// | <backref> -func (rst *rustState) demangleType() { - if len(rst.str) < 1 { - rst.fail("expected type") - } - c := rst.str[0] - if c >= 'a' && c <= 'z' { - rst.basicType() - return - } - switch c { - case 'C', 'M', 'X', 'Y', 'N', 'I': - rst.path(false) - case 'A', 'S': - rst.advance(1) - rst.writeByte('[') - rst.demangleType() - if c == 'A' { - rst.writeString("; ") - rst.demangleConst() - } - rst.writeByte(']') - case 'T': - rst.advance(1) - rst.writeByte('(') - c := 0 - for len(rst.str) > 0 && rst.str[0] != 'E' { - if c > 0 { - rst.writeString(", ") - } - c++ - rst.demangleType() - } - if c == 1 { - rst.writeByte(',') - } - rst.writeByte(')') - rst.checkChar('E') - case 'R', 'Q': - rst.advance(1) - rst.writeByte('&') - if len(rst.str) > 0 && rst.str[0] == 'L' { - rst.advance(1) - if lifetime := rst.base62Number(); lifetime > 0 { - rst.writeLifetime(lifetime) - rst.writeByte(' ') - } - } - if c == 'Q' { - rst.writeString("mut ") - } - rst.demangleType() - case 'P': - rst.advance(1) - rst.writeString("*const ") - rst.demangleType() - case 'O': - rst.advance(1) - rst.writeString("*mut ") - rst.demangleType() - case 'F': - rst.advance(1) - hold := rst.lifetimes - rst.fnSig() - rst.lifetimes = hold - case 'D': - rst.advance(1) - hold := rst.lifetimes - rst.dynBounds() - rst.lifetimes = hold - if len(rst.str) == 0 || rst.str[0] != 'L' { - rst.fail("expected L") - } - rst.advance(1) - if lifetime := rst.base62Number(); lifetime > 0 { - if rst.last != ' ' { - rst.writeByte(' ') - } - rst.writeString("+ ") - rst.writeLifetime(lifetime) - } - case 'B': - rst.backref(rst.demangleType) - default: - rst.fail("unrecognized character in type") - } -} - -var rustBasicTypes = map[byte]string{ - 'a': "i8", - 'b': "bool", - 'c': "char", - 'd': "f64", - 'e': "str", - 'f': "f32", - 'h': "u8", - 'i': "isize", - 'j': "usize", - 'l': "i32", - 'm': "u32", - 'n': "i128", - 'o': "u128", - 'p': "_", - 's': "i16", - 't': "u16", - 'u': "()", - 'v': "...", - 'x': "i64", - 'y': "u64", - 'z': "!", -} - -// basicType parses: -// -// <basic-type> -func (rst *rustState) basicType() { - if len(rst.str) < 1 { - rst.fail("expected basic type") - } - str, ok := rustBasicTypes[rst.str[0]] - if !ok { - rst.fail("unrecognized basic type character") - } - rst.advance(1) - rst.writeString(str) -} - -// fnSig parses: -// -// <fn-sig> = [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type> -// <abi> = "C" -// | <undisambiguated-identifier> -func (rst *rustState) fnSig() { - rst.binder() - if len(rst.str) > 0 && rst.str[0] == 'U' { - rst.advance(1) - rst.writeString("unsafe ") - } - if len(rst.str) > 0 && rst.str[0] == 'K' { - rst.advance(1) - if len(rst.str) > 0 && rst.str[0] == 'C' { - rst.advance(1) - rst.writeString(`extern "C" `) - } else { - rst.writeString(`extern "`) - id, isPunycode := rst.undisambiguatedIdentifier() - if isPunycode { - rst.fail("punycode used in ABI string") - } - id = strings.ReplaceAll(id, "_", "-") - rst.writeString(id) - rst.writeString(`" `) - } - } - rst.writeString("fn(") - first := true - for len(rst.str) > 0 && rst.str[0] != 'E' { - if first { - first = false - } else { - rst.writeString(", ") - } - rst.demangleType() - } - rst.checkChar('E') - rst.writeByte(')') - if len(rst.str) > 0 && rst.str[0] == 'u' { - rst.advance(1) - } else { - rst.writeString(" -> ") - rst.demangleType() - } -} - -// dynBounds parses: -// -// <dyn-bounds> = [<binder>] {<dyn-trait>} "E" -func (rst *rustState) dynBounds() { - rst.writeString("dyn ") - rst.binder() - first := true - for len(rst.str) > 0 && rst.str[0] != 'E' { - if first { - first = false - } else { - rst.writeString(" + ") - } - rst.dynTrait() - } - rst.checkChar('E') -} - -// dynTrait parses: -// -// <dyn-trait> = <path> {<dyn-trait-assoc-binding>} -// <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type> -func (rst *rustState) dynTrait() { - started := rst.pathStartGenerics() - for len(rst.str) > 0 && rst.str[0] == 'p' { - rst.advance(1) - if started { - rst.writeString(", ") - } else { - rst.writeByte('<') - started = true - } - id, _ := rst.undisambiguatedIdentifier() - rst.writeString(id) - rst.writeString(" = ") - rst.demangleType() - } - if started { - rst.writeByte('>') - } -} - -// pathStartGenerics is like path but if it sees an I to start generic -// arguments it won't close them. It reports whether it started generics. -func (rst *rustState) pathStartGenerics() bool { - if len(rst.str) < 1 { - rst.fail("expected path") - } - switch rst.str[0] { - case 'I': - rst.advance(1) - rst.path(false) - rst.writeByte('<') - rst.genericArgs() - rst.checkChar('E') - return true - case 'B': - var started bool - rst.backref(func() { started = rst.pathStartGenerics() }) - return started - default: - rst.path(false) - return false - } -} - -// writeLifetime writes out a lifetime binding. -func (rst *rustState) writeLifetime(lifetime int64) { - rst.writeByte('\'') - if lifetime == 0 { - rst.writeByte('_') - return - } - depth := rst.lifetimes - lifetime - if depth < 0 { - rst.fail("invalid lifetime") - } else if depth < 26 { - rst.writeByte('a' + byte(depth)) - } else { - rst.writeByte('z') - if !rst.skip { - fmt.Fprintf(&rst.buf, "%d", depth-26+1) - rst.last = '0' - } - } -} - -// demangleConst parses: -// -// <const> = <type> <const-data> -// | "p" // placeholder, shown as _ -// | <backref> -// <const-data> = ["n"] {<hex-digit>} "_" -func (rst *rustState) demangleConst() { - if len(rst.str) < 1 { - rst.fail("expected constant") - } - - if rst.str[0] == 'B' { - rst.backref(rst.demangleConst) - return - } - - if rst.str[0] == 'p' { - rst.advance(1) - rst.writeByte('_') - return - } - - typ := rst.str[0] - - const ( - invalid = iota - signedInt - unsignedInt - boolean - character - ) - - var kind int - switch typ { - case 'a', 's', 'l', 'x', 'n', 'i': - kind = signedInt - case 'h', 't', 'm', 'y', 'o', 'j': - kind = unsignedInt - case 'b': - kind = boolean - case 'c': - kind = character - default: - rst.fail("unrecognized constant type") - } - - rst.advance(1) - - if kind == signedInt && len(rst.str) > 0 && rst.str[0] == 'n' { - rst.advance(1) - rst.writeByte('-') - } - - start := rst.str - digits := 0 - val := uint64(0) -digitLoop: - for len(rst.str) > 0 { - c := rst.str[0] - var digit uint64 - switch { - case c >= '0' && c <= '9': - digit = uint64(c - '0') - case c >= 'a' && c <= 'f': - digit = uint64(c - 'a' + 10) - case c == '_': - rst.advance(1) - break digitLoop - default: - rst.fail("expected hex digit or _") - } - rst.advance(1) - if val == 0 && digit == 0 && (len(rst.str) == 0 || rst.str[0] != '_') { - rst.fail("invalid leading 0 in constant") - } - val *= 16 - val += digit - digits++ - } - - if digits == 0 { - rst.fail("expected constant") - } - - switch kind { - case signedInt, unsignedInt: - if digits > 16 { - // Value too big, just write out the string. - rst.writeString("0x") - rst.writeString(start[:digits]) - } else { - if !rst.skip { - fmt.Fprintf(&rst.buf, "%d", val) - rst.last = '0' - } - } - case boolean: - if digits > 1 { - rst.fail("boolean value too large") - } else if val == 0 { - rst.writeString("false") - } else if val == 1 { - rst.writeString("true") - } else { - rst.fail("invalid boolean value") - } - case character: - if digits > 6 { - rst.fail("character value too large") - } - rst.writeByte('\'') - if val == '\t' { - rst.writeString(`\t`) - } else if val == '\r' { - rst.writeString(`\r`) - } else if val == '\n' { - rst.writeString(`\n`) - } else if val == '\\' { - rst.writeString(`\\`) - } else if val == '\'' { - rst.writeString(`\'`) - } else if val >= ' ' && val <= '~' { - // printable ASCII character - rst.writeByte(byte(val)) - } else { - if !rst.skip { - fmt.Fprintf(&rst.buf, `\u{%x}`, val) - rst.last = '}' - } - } - rst.writeByte('\'') - default: - panic("internal error") - } -} - -// base62Number parses: -// -// <base-62-number> = {<0-9a-zA-Z>} "_" -func (rst *rustState) base62Number() int64 { - if len(rst.str) > 0 && rst.str[0] == '_' { - rst.advance(1) - return 0 - } - val := int64(0) - for len(rst.str) > 0 { - c := rst.str[0] - rst.advance(1) - if c == '_' { - return val + 1 - } - val *= 62 - if c >= '0' && c <= '9' { - val += int64(c - '0') - } else if c >= 'a' && c <= 'z' { - val += int64(c - 'a' + 10) - } else if c >= 'A' && c <= 'Z' { - val += int64(c - 'A' + 36) - } else { - rst.fail("invalid digit in base 62 number") - } - } - rst.fail("expected _ after base 62 number") - return 0 -} - -// backref parses: -// -// <backref> = "B" <base-62-number> -func (rst *rustState) backref(demangle func()) { - backoff := rst.off - - rst.checkChar('B') - idx64 := rst.base62Number() - - if rst.skip { - return - } - if rst.max > 0 && rst.buf.Len() > rst.max { - return - } - - idx := int(idx64) - if int64(idx) != idx64 { - rst.fail("backref index overflow") - } - if idx < 0 || idx >= backoff { - rst.fail("invalid backref index") - } - - holdStr := rst.str - holdOff := rst.off - rst.str = rst.orig[idx:backoff] - rst.off = idx - defer func() { - rst.str = holdStr - rst.off = holdOff - }() - - demangle() -} - -func (rst *rustState) decimalNumber() int { - if len(rst.str) == 0 { - rst.fail("expected number") - } - - val := 0 - for len(rst.str) > 0 && isDigit(rst.str[0]) { - add := int(rst.str[0] - '0') - if val >= math.MaxInt32/10-add { - rst.fail("decimal number overflow") - } - val *= 10 - val += add - rst.advance(1) - } - return val -} - -// oldRustToString demangles a Rust symbol using the old demangling. -// The second result reports whether this is a valid Rust mangled name. -func oldRustToString(name string, options []Option) (string, bool) { - max := 0 - for _, o := range options { - if isMaxLength(o) { - max = maxLength(o) - } - } - - // We know that the string starts with _ZN. - name = name[3:] - - hexDigit := func(c byte) (byte, bool) { - switch { - case c >= '0' && c <= '9': - return c - '0', true - case c >= 'a' && c <= 'f': - return c - 'a' + 10, true - default: - return 0, false - } - } - - // We know that the strings end with "17h" followed by 16 characters - // followed by "E". We check that the 16 characters are all hex digits. - // Also the hex digits must contain at least 5 distinct digits. - seen := uint16(0) - for i := len(name) - 17; i < len(name)-1; i++ { - digit, ok := hexDigit(name[i]) - if !ok { - return "", false - } - seen |= 1 << digit - } - if bits.OnesCount16(seen) < 5 { - return "", false - } - name = name[:len(name)-20] - - // The name is a sequence of length-preceded identifiers. - var sb strings.Builder - for len(name) > 0 { - if max > 0 && sb.Len() > max { - break - } - - if !isDigit(name[0]) { - return "", false - } - - val := 0 - for len(name) > 0 && isDigit(name[0]) { - add := int(name[0] - '0') - if val >= math.MaxInt32/10-add { - return "", false - } - val *= 10 - val += add - name = name[1:] - } - - // An optional trailing underscore can separate the - // length from the identifier. - if len(name) > 0 && name[0] == '_' { - name = name[1:] - val-- - } - - if len(name) < val { - return "", false - } - - id := name[:val] - name = name[val:] - - if sb.Len() > 0 { - sb.WriteString("::") - } - - // Ignore leading underscores preceding escape sequences. - if strings.HasPrefix(id, "_$") { - id = id[1:] - } - - // The identifier can have escape sequences. - escape: - for len(id) > 0 { - switch c := id[0]; c { - case '$': - codes := map[string]byte{ - "SP": '@', - "BP": '*', - "RF": '&', - "LT": '<', - "GT": '>', - "LP": '(', - "RP": ')', - } - - valid := true - if len(id) > 2 && id[1] == 'C' && id[2] == '$' { - sb.WriteByte(',') - id = id[3:] - } else if len(id) > 4 && id[1] == 'u' && id[4] == '$' { - dig1, ok1 := hexDigit(id[2]) - dig2, ok2 := hexDigit(id[3]) - val := (dig1 << 4) | dig2 - if !ok1 || !ok2 || dig1 > 7 || val < ' ' { - valid = false - } else { - sb.WriteByte(val) - id = id[5:] - } - } else if len(id) > 3 && id[3] == '$' { - if code, ok := codes[id[1:3]]; !ok { - valid = false - } else { - sb.WriteByte(code) - id = id[4:] - } - } else { - valid = false - } - if !valid { - sb.WriteString(id) - break escape - } - case '.': - if strings.HasPrefix(id, "..") { - sb.WriteString("::") - id = id[2:] - } else { - sb.WriteByte(c) - id = id[1:] - } - default: - sb.WriteByte(c) - id = id[1:] - } - } - } - - s := sb.String() - if max > 0 && len(s) > max { - s = s[:max] - } - return s, true -} |
