| // 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. |
| 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 |
| for _, o := range options { |
| switch o { |
| case NoTemplateParams: |
| tparams = false |
| } |
| } |
| |
| ps := printState{tparams: tparams} |
| a.print(&ps) |
| return ps.buf.String() |
| } |
| |
| // The printState type holds information needed to print an AST. |
| type printState struct { |
| tparams bool // whether to print template parameters |
| |
| 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) { |
| 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] |
| } |
| |
| // 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) |
| } |
| |
| // 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: ")) |
| } |
| |
| // 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(' ') |
| } |
| |
| ps.writeByte('<') |
| first := true |
| for _, a := range t.Args { |
| if ps.isEmpty(a) { |
| continue |
| } |
| if !first { |
| ps.writeString(", ") |
| } |
| ps.print(a) |
| first = false |
| } |
| if ps.last == '>' { |
| // Avoid syntactic ambiguity in old versions of C++. |
| ps.writeByte(' ') |
| } |
| ps.writeByte('>') |
| } |
| |
| 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. |
| 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) |
| } |
| |
| // 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.writeByte('(') |
| first := true |
| for _, e := range q.Exprs { |
| if !first { |
| ps.writeString(", ") |
| } |
| ps.print(e) |
| first = false |
| } |
| ps.writeByte(')') |
| } |
| } |
| |
| 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) { |
| ps.writeString(bt.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) |
| } |
| |
| // 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, "")) |
| } |
| |
| // VendorQualifier is a type qualified by a vendor-specific qualifier. |
| type VendorQualifier struct { |
| Qualifier AST |
| Type AST |
| } |
| |
| func (vq *VendorQualifier) print(ps *printState) { |
| 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.writeString(" (") |
| ps.printInner(false) |
| ps.writeByte(')') |
| } |
| } |
| 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. The Return field may be nil for |
| // cases where the return type is not part of the mangled name. |
| type FunctionType struct { |
| Return AST |
| Args []AST |
| } |
| |
| func (ft *FunctionType) print(ps *printState) { |
| if ft.Return != 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(ft.Return) |
| 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.writeByte('(') |
| } |
| |
| save := ps.printInner(true) |
| |
| if paren { |
| ps.writeByte(')') |
| } |
| |
| ps.writeByte('(') |
| first := true |
| for _, a := range ft.Args { |
| if ps.isEmpty(a) { |
| continue |
| } |
| if !first { |
| ps.writeString(", ") |
| } |
| ps.print(a) |
| first = false |
| } |
| ps.writeByte(')') |
| |
| 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} |
| 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 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:\n%s\n%s", indent, "", field, 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 { |
| 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) |
| } |
| |
| // 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: ")) |
| } |
| |
| // 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) { |
| ps.writeString(" __vector(") |
| ps.print(vt.Dimension) |
| ps.writeByte(')') |
| } |
| |
| 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: ")) |
| } |
| |
| // Decltype is the decltype operator. |
| type Decltype struct { |
| Expr AST |
| } |
| |
| func (dt *Decltype) print(ps *printState) { |
| ps.writeString("decltype (") |
| ps.print(dt.Expr) |
| ps.writeByte(')') |
| } |
| |
| 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 |
| } |
| |
| 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) |
| } |
| |
| // Constructor is a constructor. |
| type Constructor struct { |
| Name AST |
| } |
| |
| func (c *Constructor) print(ps *printState) { |
| ps.print(c.Name) |
| } |
| |
| func (c *Constructor) Traverse(fn func(AST) bool) { |
| if fn(c) { |
| c.Name.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) |
| if name == nil { |
| return fn(c) |
| } |
| c = &Constructor{Name: name} |
| 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 { |
| return fmt.Sprintf("%*s%sConstructor:\n%s", indent, "", field, c.Name.goString(indent+2, "Name: ")) |
| } |
| |
| // 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 { |
| 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) { |
| 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) |
| } |
| |
| // 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: ")) |
| } |
| |
| // 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, *FunctionParam: |
| case *Qualified: |
| if v.LocalName { |
| paren = true |
| } |
| default: |
| paren = true |
| } |
| if paren { |
| ps.writeByte('(') |
| } |
| ps.print(val) |
| if paren { |
| ps.writeByte(')') |
| } |
| } |
| |
| // 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) { |
| expr := u.Expr |
| |
| // Don't print the argument list when taking the address of a |
| // function. |
| if op, ok := u.Op.(*Operator); ok && op.Name == "&" { |
| if t, ok := expr.(*Typed); ok { |
| if _, ok := t.Type.(*FunctionType); ok { |
| expr = t.Name |
| } |
| } |
| } |
| |
| if u.Suffix { |
| parenthesize(ps, expr) |
| } |
| |
| if op, ok := u.Op.(*Operator); ok { |
| ps.writeString(op.Name) |
| } else if c, ok := u.Op.(*Cast); ok { |
| ps.writeByte('(') |
| ps.print(c.To) |
| ps.writeByte(')') |
| } else { |
| ps.print(u.Op) |
| } |
| |
| if !u.Suffix { |
| if op, ok := u.Op.(*Operator); ok && op.Name == "::" { |
| // Don't use parentheses after ::. |
| ps.print(expr) |
| } else if u.SizeofType { |
| // Always use parentheses for sizeof argument. |
| ps.writeByte('(') |
| ps.print(expr) |
| ps.writeByte(')') |
| } 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: ")) |
| } |
| |
| // 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 { |
| return op.Name == "=" || op.Name == "]=" |
| } |
| 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) |
| ps.writeByte('<') |
| ps.print(b.Left) |
| ps.writeString(">(") |
| ps.print(b.Right) |
| ps.writeByte(')') |
| 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 { |
| 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. |
| if op != nil && op.Name == ">" { |
| ps.writeByte('(') |
| } |
| |
| left := b.Left |
| |
| // For a function call in an expression, don't print the types |
| // of the arguments unless there is a return type. |
| skipParens := false |
| 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 skipParens { |
| ps.print(left) |
| } else { |
| parenthesize(ps, left) |
| } |
| |
| if op != nil && op.Name == "[]" { |
| ps.writeByte('[') |
| ps.print(b.Right) |
| ps.writeByte(']') |
| return |
| } |
| |
| if op != nil { |
| if op.Name != "()" { |
| ps.writeString(op.Name) |
| } |
| } else { |
| ps.print(b.Op) |
| } |
| |
| parenthesize(ps, b.Right) |
| |
| if op != nil && op.Name == ">" { |
| ps.writeByte(')') |
| } |
| } |
| |
| 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: ")) |
| } |
| |
| // 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 { |
| ps.writeByte('=') |
| parenthesize(ps, t.Third) |
| } |
| return |
| } |
| |
| parenthesize(ps, t.First) |
| ps.writeByte('?') |
| parenthesize(ps, t.Second) |
| ps.writeString(" : ") |
| 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 { |
| ps.writeString(op.Name) |
| } else { |
| ps.print(f.Op) |
| } |
| } |
| |
| if f.Arg2 == nil { |
| if f.Left { |
| ps.writeString("(...") |
| printOp() |
| parenthesize(ps, f.Arg1) |
| ps.writeString(")") |
| } else { |
| ps.writeString("(") |
| parenthesize(ps, f.Arg1) |
| printOp() |
| ps.writeString("...)") |
| } |
| } else { |
| ps.writeString("(") |
| parenthesize(ps, f.Arg1) |
| printOp() |
| ps.writeString("...") |
| printOp() |
| parenthesize(ps, f.Arg2) |
| ps.writeString(")") |
| } |
| } |
| |
| 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: ")) |
| } |
| } |
| |
| // 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) { |
| // Op doesn't really matter for printing--we always print "new". |
| ps.writeString("new ") |
| 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 == "" { |
| ps.print(l.Type) |
| return |
| } else { |
| isFloat = builtinTypeFloat[b.Name] |
| } |
| } |
| |
| ps.writeByte('(') |
| ps.print(l.Type) |
| ps.writeByte(')') |
| |
| 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) |
| } |
| |
| // 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) { |
| for i, e := range el.Exprs { |
| if i > 0 { |
| ps.writeString(", ") |
| } |
| ps.print(e) |
| } |
| } |
| |
| 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 |
| } |
| |
| // 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) { |
| 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 { |
| Types []AST |
| Num int |
| } |
| |
| func (cl *Closure) print(ps *printState) { |
| ps.writeString("{lambda(") |
| for i, t := range cl.Types { |
| if i > 0 { |
| ps.writeString(", ") |
| } |
| ps.print(t) |
| } |
| ps.writeString(fmt.Sprintf(")#%d}", cl.Num+1)) |
| } |
| |
| func (cl *Closure) Traverse(fn func(AST) bool) { |
| if fn(cl) { |
| for _, t := range cl.Types { |
| t.Traverse(fn) |
| } |
| } |
| } |
| |
| func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST { |
| if skip(cl) { |
| return nil |
| } |
| types := make([]AST, len(cl.Types)) |
| changed := false |
| for i, t := range cl.Types { |
| tc := t.Copy(fn, skip) |
| if tc == nil { |
| types[i] = t |
| } else { |
| types[i] = tc |
| changed = true |
| } |
| } |
| if !changed { |
| return fn(cl) |
| } |
| cl = &Closure{Types: types, Num: cl.Num} |
| 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 types string |
| if len(cl.Types) == 0 { |
| types = fmt.Sprintf("%*sTypes: nil", indent+2, "") |
| } else { |
| types = fmt.Sprintf("%*sTypes:", indent+2, "") |
| for i, t := range cl.Types { |
| types += "\n" |
| types += t.goString(indent+4, fmt.Sprintf("%d: ", i)) |
| } |
| } |
| return fmt.Sprintf("%*s%sClosure: Num: %d\n%s", indent, "", field, cl.Num, types) |
| } |
| |
| // UnnamedType is an unnamed type, that just has an index. |
| type UnnamedType struct { |
| Num int |
| } |
| |
| func (ut *UnnamedType) print(ps *printState) { |
| 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) |
| 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) { |
| ps.writeString(s.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:") |
| first := true |
| for _, a := range ei.Args { |
| if !first { |
| ps.writeString(", ") |
| } |
| ps.print(a) |
| first = false |
| } |
| 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) |
| } |
| |
| // 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: |
| return len(a.Args) == 0 |
| case *ExprList: |
| return len(a.Exprs) == 0 |
| case *PackExpansion: |
| return a.Pack != nil && ps.isEmpty(a.Base) |
| default: |
| return false |
| } |
| } |