aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/ianlancetaylor
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2025-01-22 16:07:17 +0100
committerTaras Madan <tarasmadan@google.com>2025-01-23 10:42:36 +0000
commit7b4377ad9d8a7205416df8d6217ef2b010f89481 (patch)
treee6fec4fd12ff807a16d847923f501075bf71d16c /vendor/github.com/ianlancetaylor
parent475a4c203afb8b7d3af51c4fd32bb170ff32a45e (diff)
vendor: delete
Diffstat (limited to 'vendor/github.com/ianlancetaylor')
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/.gitignore13
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/LICENSE27
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/README.md3
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/SECURITY.md13
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/ast.go5256
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/demangle.go3689
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/rust.go1165
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(&params, "%*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(&params, "%*sParams: nil", indent+2, "")
- } else {
- fmt.Fprintf(&params, "%*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
-}