2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2011 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 gc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"cmd/internal/obj"
|
|
|
|
|
"fmt"
|
2015-03-12 18:45:30 -04:00
|
|
|
"strconv"
|
2015-02-13 14:40:36 -05:00
|
|
|
"strings"
|
|
|
|
|
"unicode/utf8"
|
|
|
|
|
)
|
|
|
|
|
|
2016-09-09 21:08:46 -07:00
|
|
|
// TODO(gri) update documentation thoroughly
|
|
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
// A FmtFlag value is a set of flags (or 0).
|
|
|
|
|
// They control how the Xconv functions format their values.
|
|
|
|
|
// See the respective function's documentation for details.
|
|
|
|
|
type FmtFlag int
|
|
|
|
|
|
2016-09-09 21:08:46 -07:00
|
|
|
const ( // fmt.Format flag/prec or verb
|
2016-08-30 14:13:41 -07:00
|
|
|
FmtLeft FmtFlag = 1 << iota // "-" => '-'
|
|
|
|
|
FmtSharp // "#" => '#'
|
|
|
|
|
FmtSign // "+" => '+'
|
|
|
|
|
FmtUnsigned // "u" => ' '
|
2016-09-09 21:08:46 -07:00
|
|
|
FmtShort // "h" => verb == 'S' (Short)
|
|
|
|
|
FmtLong // "l" => verb == 'L' (Long)
|
2016-08-30 14:13:41 -07:00
|
|
|
FmtComma // "," => '.' (== hasPrec)
|
|
|
|
|
FmtByte // "hh" => '0'
|
2016-03-15 13:06:58 -07:00
|
|
|
)
|
|
|
|
|
|
2016-09-08 16:51:26 -07:00
|
|
|
func fmtFlag(s fmt.State, verb rune) FmtFlag {
|
2016-08-30 14:13:41 -07:00
|
|
|
var flag FmtFlag
|
|
|
|
|
if s.Flag('-') {
|
|
|
|
|
flag |= FmtLeft
|
|
|
|
|
}
|
|
|
|
|
if s.Flag('#') {
|
|
|
|
|
flag |= FmtSharp
|
|
|
|
|
}
|
|
|
|
|
if s.Flag('+') {
|
|
|
|
|
flag |= FmtSign
|
|
|
|
|
}
|
|
|
|
|
if s.Flag(' ') {
|
|
|
|
|
flag |= FmtUnsigned
|
|
|
|
|
}
|
|
|
|
|
if _, ok := s.Precision(); ok {
|
|
|
|
|
flag |= FmtComma
|
|
|
|
|
}
|
|
|
|
|
if s.Flag('0') {
|
|
|
|
|
flag |= FmtByte
|
|
|
|
|
}
|
2016-09-08 16:51:26 -07:00
|
|
|
switch verb {
|
|
|
|
|
case 'S':
|
|
|
|
|
flag |= FmtShort
|
|
|
|
|
case 'L':
|
|
|
|
|
flag |= FmtLong
|
|
|
|
|
}
|
2016-08-30 14:13:41 -07:00
|
|
|
return flag
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
//
|
|
|
|
|
// Format conversions
|
|
|
|
|
// %L int Line numbers
|
|
|
|
|
//
|
|
|
|
|
// %E int etype values (aka 'Kind')
|
|
|
|
|
//
|
|
|
|
|
// %O int Node Opcodes
|
|
|
|
|
// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
|
|
|
|
|
//
|
|
|
|
|
// %J Node* Node details
|
|
|
|
|
// Flags: "%hJ" suppresses things not relevant until walk.
|
|
|
|
|
//
|
|
|
|
|
// %V Val* Constant values
|
|
|
|
|
//
|
|
|
|
|
// %S Sym* Symbols
|
|
|
|
|
// Flags: +,- #: mode (see below)
|
|
|
|
|
// "%hS" unqualified identifier in any mode
|
|
|
|
|
// "%hhS" in export mode: unqualified identifier if exported, qualified if not
|
|
|
|
|
//
|
|
|
|
|
// %T Type* Types
|
|
|
|
|
// Flags: +,- #: mode (see below)
|
|
|
|
|
// 'l' definition instead of name.
|
|
|
|
|
// 'h' omit "func" and receiver in function types
|
|
|
|
|
// 'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
|
|
|
|
|
//
|
|
|
|
|
// %N Node* Nodes
|
|
|
|
|
// Flags: +,- #: mode (see below)
|
|
|
|
|
// 'h' (only in +/debug mode) suppress recursion
|
|
|
|
|
// 'l' (only in Error mode) print "foo (type Bar)"
|
|
|
|
|
//
|
2016-03-10 10:00:29 -08:00
|
|
|
// %H Nodes Nodes
|
2015-02-13 14:40:36 -05:00
|
|
|
// Flags: those of %N
|
|
|
|
|
// ',' separate items with ',' instead of ';'
|
|
|
|
|
//
|
2015-10-22 09:51:12 +09:00
|
|
|
// In mparith2.go and mparith3.go:
|
|
|
|
|
// %B Mpint* Big integers
|
|
|
|
|
// %F Mpflt* Big floats
|
2015-02-13 14:40:36 -05:00
|
|
|
//
|
|
|
|
|
// %S, %T and %N obey use the following flags to set the format mode:
|
|
|
|
|
const (
|
|
|
|
|
FErr = iota
|
|
|
|
|
FDbg
|
|
|
|
|
FTypeId
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var fmtmode int = FErr
|
|
|
|
|
|
|
|
|
|
var fmtpkgpfx int // %uT stickyness
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// E.g. for %S: %+S %#S %-S print an identifier properly qualified for debug/export/internal mode.
|
|
|
|
|
//
|
|
|
|
|
// The mode flags +, - and # are sticky, meaning they persist through
|
2016-03-01 23:21:55 +00:00
|
|
|
// recursions of %N, %T and %S, but not the h and l flags. The u flag is
|
2015-02-13 14:40:36 -05:00
|
|
|
// sticky only on %T recursions and only used in %-/Sym mode.
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Useful format combinations:
|
|
|
|
|
//
|
|
|
|
|
// %+N %+H multiline recursive debug dump of node/nodelist
|
|
|
|
|
// %+hN %+hH non recursive debug dump
|
|
|
|
|
//
|
|
|
|
|
// %#N %#T export format
|
|
|
|
|
// %#lT type definition instead of name
|
|
|
|
|
// %#hT omit"func" and receiver in function signature
|
|
|
|
|
//
|
|
|
|
|
// %lN "foo (type Bar)" for error messages
|
|
|
|
|
//
|
|
|
|
|
// %-T type identifiers
|
|
|
|
|
// %-hT type identifiers without "func" and arg names in type signatures (methodsym)
|
|
|
|
|
// %-uT type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
|
|
|
|
|
//
|
|
|
|
|
|
2016-08-30 11:19:07 -07:00
|
|
|
func setfmode(flags *FmtFlag) (fm int) {
|
2015-12-30 19:47:36 -05:00
|
|
|
fm = fmtmode
|
2016-03-15 13:06:58 -07:00
|
|
|
if *flags&FmtSign != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
fmtmode = FDbg
|
2016-03-15 13:06:58 -07:00
|
|
|
} else if *flags&FmtSharp != 0 {
|
2016-08-22 15:56:27 -07:00
|
|
|
// ignore (textual export format no longer supported)
|
2016-03-15 13:06:58 -07:00
|
|
|
} else if *flags&FmtLeft != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
fmtmode = FTypeId
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 11:19:07 -07:00
|
|
|
*flags &^= (FmtSharp | FmtLeft | FmtSign)
|
2015-12-30 19:47:36 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fmt "%L": Linenumbers
|
|
|
|
|
|
|
|
|
|
var goopnames = []string{
|
|
|
|
|
OADDR: "&",
|
|
|
|
|
OADD: "+",
|
|
|
|
|
OADDSTR: "+",
|
|
|
|
|
OANDAND: "&&",
|
|
|
|
|
OANDNOT: "&^",
|
|
|
|
|
OAND: "&",
|
|
|
|
|
OAPPEND: "append",
|
|
|
|
|
OAS: "=",
|
|
|
|
|
OAS2: "=",
|
|
|
|
|
OBREAK: "break",
|
|
|
|
|
OCALL: "function call", // not actual syntax
|
|
|
|
|
OCAP: "cap",
|
|
|
|
|
OCASE: "case",
|
|
|
|
|
OCLOSE: "close",
|
|
|
|
|
OCOMPLEX: "complex",
|
|
|
|
|
OCOM: "^",
|
|
|
|
|
OCONTINUE: "continue",
|
|
|
|
|
OCOPY: "copy",
|
|
|
|
|
ODEC: "--",
|
|
|
|
|
ODELETE: "delete",
|
|
|
|
|
ODEFER: "defer",
|
|
|
|
|
ODIV: "/",
|
|
|
|
|
OEQ: "==",
|
|
|
|
|
OFALL: "fallthrough",
|
|
|
|
|
OFOR: "for",
|
|
|
|
|
OGE: ">=",
|
|
|
|
|
OGOTO: "goto",
|
|
|
|
|
OGT: ">",
|
|
|
|
|
OIF: "if",
|
|
|
|
|
OIMAG: "imag",
|
|
|
|
|
OINC: "++",
|
|
|
|
|
OIND: "*",
|
|
|
|
|
OLEN: "len",
|
|
|
|
|
OLE: "<=",
|
|
|
|
|
OLSH: "<<",
|
|
|
|
|
OLT: "<",
|
|
|
|
|
OMAKE: "make",
|
|
|
|
|
OMINUS: "-",
|
|
|
|
|
OMOD: "%",
|
|
|
|
|
OMUL: "*",
|
|
|
|
|
ONEW: "new",
|
|
|
|
|
ONE: "!=",
|
|
|
|
|
ONOT: "!",
|
|
|
|
|
OOROR: "||",
|
|
|
|
|
OOR: "|",
|
|
|
|
|
OPANIC: "panic",
|
|
|
|
|
OPLUS: "+",
|
|
|
|
|
OPRINTN: "println",
|
|
|
|
|
OPRINT: "print",
|
|
|
|
|
ORANGE: "range",
|
|
|
|
|
OREAL: "real",
|
|
|
|
|
ORECV: "<-",
|
|
|
|
|
ORECOVER: "recover",
|
|
|
|
|
ORETURN: "return",
|
|
|
|
|
ORSH: ">>",
|
|
|
|
|
OSELECT: "select",
|
|
|
|
|
OSEND: "<-",
|
|
|
|
|
OSUB: "-",
|
|
|
|
|
OSWITCH: "switch",
|
|
|
|
|
OXOR: "^",
|
2016-04-01 23:28:14 -05:00
|
|
|
OXFALL: "fallthrough",
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-04-27 19:34:17 +10:00
|
|
|
func (o Op) String() string {
|
2016-08-31 14:12:35 -07:00
|
|
|
return fmt.Sprint(o)
|
2016-04-27 19:34:17 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o Op) GoString() string {
|
2016-08-30 14:21:33 -07:00
|
|
|
return fmt.Sprintf("%#v", o)
|
2016-04-27 19:34:17 +10:00
|
|
|
}
|
|
|
|
|
|
2016-09-08 16:51:26 -07:00
|
|
|
func (o Op) Format(s fmt.State, verb rune) {
|
|
|
|
|
switch verb {
|
2016-09-09 21:08:46 -07:00
|
|
|
case 'v':
|
2016-09-08 16:51:26 -07:00
|
|
|
o.oconv(s, fmtFlag(s, verb))
|
2016-08-30 14:21:33 -07:00
|
|
|
|
|
|
|
|
default:
|
2016-09-08 16:51:26 -07:00
|
|
|
fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o))
|
2016-08-30 14:21:33 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 16:51:26 -07:00
|
|
|
func (o Op) oconv(s fmt.State, flag FmtFlag) {
|
2016-03-15 13:06:58 -07:00
|
|
|
if (flag&FmtSharp != 0) || fmtmode != FDbg {
|
2016-03-07 08:23:55 -08:00
|
|
|
if o >= 0 && int(o) < len(goopnames) && goopnames[o] != "" {
|
2016-08-30 14:21:33 -07:00
|
|
|
fmt.Fprint(s, goopnames[o])
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-07 08:23:55 -08:00
|
|
|
if o >= 0 && int(o) < len(opnames) && opnames[o] != "" {
|
2016-08-30 14:21:33 -07:00
|
|
|
fmt.Fprint(s, opnames[o])
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-09-08 16:51:26 -07:00
|
|
|
fmt.Fprintf(s, "O-%d", int(o))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var classnames = []string{
|
|
|
|
|
"Pxxx",
|
|
|
|
|
"PEXTERN",
|
|
|
|
|
"PAUTO",
|
cmd/compile: fix liveness computation for heap-escaped parameters
The liveness computation of parameters generally was never
correct, but forcing all parameters to be live throughout the
function covered up that problem. The new SSA back end is
too clever: even though it currently keeps the parameter values live
throughout the function, it may find optimizations that mean
the current values are not written back to the original parameter
stack slots immediately or ever (for example if a parameter is set
to nil, SSA constant propagation may replace all later uses of the
parameter with a constant nil, eliminating the need to write the nil
value back to the stack slot), so the liveness code must now
track the actual operations on the stack slots, exposing these
problems.
One small problem in the handling of arguments is that nodarg
can return ONAME PPARAM nodes with adjusted offsets, so that
there are actually multiple *Node pointers for the same parameter
in the instruction stream. This might be possible to correct, but
not in this CL. For now, we fix this by using n.Orig instead of n
when considering PPARAM and PPARAMOUT nodes.
The major problem in the handling of arguments is general
confusion in the liveness code about the meaning of PPARAM|PHEAP
and PPARAMOUT|PHEAP nodes, especially as contrasted with PAUTO|PHEAP.
The difference between these two is that when a local variable "moves"
to the heap, it's really just allocated there to start with; in contrast,
when an argument moves to the heap, the actual data has to be copied
there from the stack at the beginning of the function, and when a
result "moves" to the heap the value in the heap has to be copied
back to the stack when the function returns
This general confusion is also present in the SSA back end.
The PHEAP bit worked decently when I first introduced it 7 years ago (!)
in 391425ae. The back end did nothing sophisticated, and in particular
there was no analysis at all: no escape analysis, no liveness analysis,
and certainly no SSA back end. But the complications caused in the
various downstream consumers suggest that this should be a detail
kept mainly in the front end.
This CL therefore eliminates both the PHEAP bit and even the idea of
"heap variables" from the back ends.
First, it replaces the PPARAM|PHEAP, PPARAMOUT|PHEAP, and PAUTO|PHEAP
variable classes with the single PAUTOHEAP, a pseudo-class indicating
a variable maintained on the heap and available by indirecting a
local variable kept on the stack (a plain PAUTO).
Second, walkexpr replaces all references to PAUTOHEAP variables
with indirections of the corresponding PAUTO variable.
The back ends and the liveness code now just see plain indirected
variables. This may actually produce better code, but the real goal
here is to eliminate these little-used and somewhat suspect code
paths in the back end analyses.
The OPARAM node type goes away too.
A followup CL will do the same to PPARAMREF. I'm not sure that
the back ends (SSA in particular) are handling those right either,
and with the framework established in this CL that change is trivial
and the result clearly more correct.
Fixes #15747.
Change-Id: I2770b1ce3cbc93981bfc7166be66a9da12013d74
Reviewed-on: https://go-review.googlesource.com/23393
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-05-25 01:33:24 -04:00
|
|
|
"PAUTOHEAP",
|
2015-02-13 14:40:36 -05:00
|
|
|
"PPARAM",
|
|
|
|
|
"PPARAMOUT",
|
|
|
|
|
"PFUNC",
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 16:51:26 -07:00
|
|
|
func (n *Node) Format(s fmt.State, verb rune) {
|
|
|
|
|
switch verb {
|
2016-09-09 21:08:46 -07:00
|
|
|
case 'v', 'S', 'L':
|
2016-09-08 16:51:26 -07:00
|
|
|
n.Nconv(s, fmtFlag(s, verb))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-08-30 14:13:41 -07:00
|
|
|
case 'j':
|
2016-09-08 16:51:26 -07:00
|
|
|
n.jconv(s, fmtFlag(s, verb))
|
2016-08-30 14:13:41 -07:00
|
|
|
|
|
|
|
|
default:
|
2016-09-08 16:51:26 -07:00
|
|
|
fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n)
|
2016-08-30 14:13:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Node details
|
2016-09-08 16:51:26 -07:00
|
|
|
func (n *Node) jconv(s fmt.State, flag FmtFlag) {
|
|
|
|
|
c := flag & FmtShort
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if c == 0 && n.Ullman != 0 {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " u(%d)", n.Ullman)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-04-02 19:58:37 -07:00
|
|
|
if c == 0 && n.Addable {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " a(%v)", n.Addable)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-05-26 23:56:14 -04:00
|
|
|
if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Lineno != 0 {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " l(%d)", n.Lineno)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if c == 0 && n.Xoffset != BADWIDTH {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " x(%d%+d)", n.Xoffset, stkdelta[n])
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Class != 0 {
|
cmd/compile: fix liveness computation for heap-escaped parameters
The liveness computation of parameters generally was never
correct, but forcing all parameters to be live throughout the
function covered up that problem. The new SSA back end is
too clever: even though it currently keeps the parameter values live
throughout the function, it may find optimizations that mean
the current values are not written back to the original parameter
stack slots immediately or ever (for example if a parameter is set
to nil, SSA constant propagation may replace all later uses of the
parameter with a constant nil, eliminating the need to write the nil
value back to the stack slot), so the liveness code must now
track the actual operations on the stack slots, exposing these
problems.
One small problem in the handling of arguments is that nodarg
can return ONAME PPARAM nodes with adjusted offsets, so that
there are actually multiple *Node pointers for the same parameter
in the instruction stream. This might be possible to correct, but
not in this CL. For now, we fix this by using n.Orig instead of n
when considering PPARAM and PPARAMOUT nodes.
The major problem in the handling of arguments is general
confusion in the liveness code about the meaning of PPARAM|PHEAP
and PPARAMOUT|PHEAP nodes, especially as contrasted with PAUTO|PHEAP.
The difference between these two is that when a local variable "moves"
to the heap, it's really just allocated there to start with; in contrast,
when an argument moves to the heap, the actual data has to be copied
there from the stack at the beginning of the function, and when a
result "moves" to the heap the value in the heap has to be copied
back to the stack when the function returns
This general confusion is also present in the SSA back end.
The PHEAP bit worked decently when I first introduced it 7 years ago (!)
in 391425ae. The back end did nothing sophisticated, and in particular
there was no analysis at all: no escape analysis, no liveness analysis,
and certainly no SSA back end. But the complications caused in the
various downstream consumers suggest that this should be a detail
kept mainly in the front end.
This CL therefore eliminates both the PHEAP bit and even the idea of
"heap variables" from the back ends.
First, it replaces the PPARAM|PHEAP, PPARAMOUT|PHEAP, and PAUTO|PHEAP
variable classes with the single PAUTOHEAP, a pseudo-class indicating
a variable maintained on the heap and available by indirecting a
local variable kept on the stack (a plain PAUTO).
Second, walkexpr replaces all references to PAUTOHEAP variables
with indirections of the corresponding PAUTO variable.
The back ends and the liveness code now just see plain indirected
variables. This may actually produce better code, but the real goal
here is to eliminate these little-used and somewhat suspect code
paths in the back end analyses.
The OPARAM node type goes away too.
A followup CL will do the same to PPARAMREF. I'm not sure that
the back ends (SSA in particular) are handling those right either,
and with the framework established in this CL that change is trivial
and the result clearly more correct.
Fixes #15747.
Change-Id: I2770b1ce3cbc93981bfc7166be66a9da12013d74
Reviewed-on: https://go-review.googlesource.com/23393
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-05-25 01:33:24 -04:00
|
|
|
if int(n.Class) < len(classnames) {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " class(%s)", classnames[n.Class])
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " class(%d?)", n.Class)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-02 19:58:37 -07:00
|
|
|
if n.Colas {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " colas(%v)", n.Colas)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-05-27 00:44:05 -04:00
|
|
|
if n.Name != nil && n.Name.Funcdepth != 0 {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " f(%d)", n.Name.Funcdepth)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-06-03 14:16:01 -04:00
|
|
|
if n.Func != nil && n.Func.Depth != 0 {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " ff(%d)", n.Func.Depth)
|
2015-06-03 14:16:01 -04:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
switch n.Esc {
|
|
|
|
|
case EscUnknown:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case EscHeap:
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprint(s, " esc(h)")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case EscScope:
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprint(s, " esc(s)")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case EscNone:
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprint(s, " esc(no)")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case EscNever:
|
2015-02-17 22:13:49 -05:00
|
|
|
if c == 0 {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprint(s, " esc(N)")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " esc(%d)", n.Esc)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-05-27 00:47:05 -04:00
|
|
|
if e, ok := n.Opt().(*NodeEscState); ok && e.Escloopdepth != 0 {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " ld(%d)", e.Escloopdepth)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if c == 0 && n.Typecheck != 0 {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " tc(%d)", n.Typecheck)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-05-16 14:23:12 -07:00
|
|
|
if c == 0 && n.IsStatic {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprint(s, " static")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-09 16:24:07 +11:00
|
|
|
if n.Isddd {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " isddd(%v)", n.Isddd)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-06 21:18:41 +11:00
|
|
|
if n.Implicit {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " implicit(%v)", n.Implicit)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Embedded != 0 {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " embedded(%d)", n.Embedded)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-05 18:20:54 +11:00
|
|
|
if n.Addrtaken {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprint(s, " addrtaken")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-06 18:42:58 +11:00
|
|
|
if n.Assigned {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprint(s, " assigned")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-04-19 21:06:53 -07:00
|
|
|
if n.Bounded {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprint(s, " bounded")
|
2016-04-19 21:06:53 -07:00
|
|
|
}
|
|
|
|
|
if n.NonNil {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprint(s, " nonnil")
|
2016-04-19 21:06:53 -07:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-06 21:18:41 +11:00
|
|
|
if c == 0 && n.Used {
|
2016-08-30 14:13:41 -07:00
|
|
|
fmt.Fprintf(s, " used(%v)", n.Used)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 16:51:26 -07:00
|
|
|
func (v Val) Format(s fmt.State, verb rune) {
|
|
|
|
|
switch verb {
|
2016-09-09 21:08:46 -07:00
|
|
|
case 'v':
|
2016-09-08 16:51:26 -07:00
|
|
|
v.vconv(s, fmtFlag(s, verb))
|
2016-08-30 15:01:48 -07:00
|
|
|
|
|
|
|
|
default:
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, "%%!%c(Val=%T)", verb, v)
|
2016-08-30 15:01:48 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// Fmt "%V": Values
|
2016-09-08 16:51:26 -07:00
|
|
|
func (v Val) vconv(s fmt.State, flag FmtFlag) {
|
2016-04-22 12:27:29 -07:00
|
|
|
switch u := v.U.(type) {
|
|
|
|
|
case *Mpint:
|
|
|
|
|
if !u.Rune {
|
2016-08-16 12:55:17 -07:00
|
|
|
if flag&FmtSharp != 0 {
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprint(s, bconv(u, FmtSharp))
|
|
|
|
|
return
|
2016-04-22 12:27:29 -07:00
|
|
|
}
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprint(s, bconv(u, 0))
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-24 22:15:07 -07:00
|
|
|
switch x := u.Int64(); {
|
|
|
|
|
case ' ' <= x && x < utf8.RuneSelf && x != '\\' && x != '\'':
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprintf(s, "'%c'", int(x))
|
2016-08-24 22:15:07 -07:00
|
|
|
|
|
|
|
|
case 0 <= x && x < 1<<16:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprintf(s, "'\\u%04x'", uint(int(x)))
|
2016-08-24 22:15:07 -07:00
|
|
|
|
|
|
|
|
case 0 <= x && x <= utf8.MaxRune:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprintf(s, "'\\U%08x'", uint64(x))
|
2016-08-24 22:15:07 -07:00
|
|
|
|
|
|
|
|
default:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprintf(s, "('\\x00' + %v)", u)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-04-22 12:27:29 -07:00
|
|
|
case *Mpflt:
|
2016-08-16 12:55:17 -07:00
|
|
|
if flag&FmtSharp != 0 {
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprint(s, fconv(u, 0))
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprint(s, fconv(u, FmtSharp))
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-04-22 12:27:29 -07:00
|
|
|
case *Mpcplx:
|
2016-08-24 22:15:07 -07:00
|
|
|
switch {
|
|
|
|
|
case flag&FmtSharp != 0:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprintf(s, "(%v+%vi)", &u.Real, &u.Imag)
|
2016-08-24 22:15:07 -07:00
|
|
|
|
|
|
|
|
case v.U.(*Mpcplx).Real.CmpFloat64(0) == 0:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprintf(s, "%vi", fconv(&u.Imag, FmtSharp))
|
2016-08-24 22:15:07 -07:00
|
|
|
|
|
|
|
|
case v.U.(*Mpcplx).Imag.CmpFloat64(0) == 0:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprint(s, fconv(&u.Real, FmtSharp))
|
2016-08-24 22:15:07 -07:00
|
|
|
|
|
|
|
|
case v.U.(*Mpcplx).Imag.CmpFloat64(0) < 0:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprintf(s, "(%v%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
|
2016-08-24 22:15:07 -07:00
|
|
|
|
|
|
|
|
default:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprintf(s, "(%v+%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-04-22 12:27:29 -07:00
|
|
|
case string:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprint(s, strconv.Quote(u))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-04-22 12:27:29 -07:00
|
|
|
case bool:
|
2016-08-30 15:01:48 -07:00
|
|
|
t := "false"
|
2016-04-22 12:27:29 -07:00
|
|
|
if u {
|
2016-08-30 15:01:48 -07:00
|
|
|
t = "true"
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprint(s, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-04-22 12:27:29 -07:00
|
|
|
case *NilVal:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprint(s, "nil")
|
2016-08-24 22:15:07 -07:00
|
|
|
|
|
|
|
|
default:
|
2016-08-30 15:01:48 -07:00
|
|
|
fmt.Fprintf(s, "<ctype=%d>", v.Ctype())
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
s%,%,\n%g
|
|
|
|
|
s%\n+%\n%g
|
|
|
|
|
s%^[ ]*T%%g
|
|
|
|
|
s%,.*%%g
|
|
|
|
|
s%.+% [T&] = "&",%g
|
|
|
|
|
s%^ ........*\]%&~%g
|
|
|
|
|
s%~ %%g
|
|
|
|
|
*/
|
|
|
|
|
var etnames = []string{
|
2016-03-27 15:31:50 -07:00
|
|
|
Txxx: "Txxx",
|
2015-02-13 14:40:36 -05:00
|
|
|
TINT: "INT",
|
|
|
|
|
TUINT: "UINT",
|
|
|
|
|
TINT8: "INT8",
|
|
|
|
|
TUINT8: "UINT8",
|
|
|
|
|
TINT16: "INT16",
|
|
|
|
|
TUINT16: "UINT16",
|
|
|
|
|
TINT32: "INT32",
|
|
|
|
|
TUINT32: "UINT32",
|
|
|
|
|
TINT64: "INT64",
|
|
|
|
|
TUINT64: "UINT64",
|
|
|
|
|
TUINTPTR: "UINTPTR",
|
|
|
|
|
TFLOAT32: "FLOAT32",
|
|
|
|
|
TFLOAT64: "FLOAT64",
|
|
|
|
|
TCOMPLEX64: "COMPLEX64",
|
|
|
|
|
TCOMPLEX128: "COMPLEX128",
|
|
|
|
|
TBOOL: "BOOL",
|
|
|
|
|
TPTR32: "PTR32",
|
|
|
|
|
TPTR64: "PTR64",
|
|
|
|
|
TFUNC: "FUNC",
|
|
|
|
|
TARRAY: "ARRAY",
|
2016-04-18 14:02:08 -07:00
|
|
|
TSLICE: "SLICE",
|
2015-02-13 14:40:36 -05:00
|
|
|
TSTRUCT: "STRUCT",
|
|
|
|
|
TCHAN: "CHAN",
|
|
|
|
|
TMAP: "MAP",
|
|
|
|
|
TINTER: "INTER",
|
|
|
|
|
TFORW: "FORW",
|
|
|
|
|
TSTRING: "STRING",
|
2015-07-22 19:18:35 -07:00
|
|
|
TUNSAFEPTR: "TUNSAFEPTR",
|
2015-02-13 14:40:36 -05:00
|
|
|
TANY: "ANY",
|
2016-03-27 15:31:50 -07:00
|
|
|
TIDEAL: "TIDEAL",
|
|
|
|
|
TNIL: "TNIL",
|
|
|
|
|
TBLANK: "TBLANK",
|
|
|
|
|
TFUNCARGS: "TFUNCARGS",
|
|
|
|
|
TCHANARGS: "TCHANARGS",
|
|
|
|
|
TINTERMETH: "TINTERMETH",
|
|
|
|
|
TDDDFIELD: "TDDDFIELD",
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
cmd/compile/internal/gc: unexport {J,S,F,H,B,V}conv
Updates #15462
Unexport Jconv, Sconv, Fconv, Hconv, Bconv, and VConv as they are
not referenced outside internal/gc.
Econv was only called by EType.String, so merge it into that method.
Change-Id: Iad9b06078eb513b85a03a43cd9eb9366477643d1
Reviewed-on: https://go-review.googlesource.com/22531
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Dave Cheney <dave@cheney.net>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-04-27 15:15:47 +10:00
|
|
|
func (et EType) String() string {
|
2015-09-24 23:21:18 +02:00
|
|
|
if int(et) < len(etnames) && etnames[et] != "" {
|
2015-02-27 22:44:15 +00:00
|
|
|
return etnames[et]
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-27 22:44:15 +00:00
|
|
|
return fmt.Sprintf("E-%d", et)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fmt "%S": syms
|
2016-08-31 14:12:35 -07:00
|
|
|
func (s *Sym) symfmt(f fmt.State, flag FmtFlag) {
|
2016-03-15 13:06:58 -07:00
|
|
|
if s.Pkg != nil && flag&FmtShort == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch fmtmode {
|
|
|
|
|
case FErr: // This is for the user
|
2016-01-19 14:17:29 -08:00
|
|
|
if s.Pkg == builtinpkg || s.Pkg == localpkg {
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(f, s.Name)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the name was used by multiple packages, display the full path,
|
2015-03-02 16:21:15 -05:00
|
|
|
if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprintf(f, "%q.%s", s.Pkg.Path, s.Name)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(f, s.Pkg.Name+"."+s.Name)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case FDbg:
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(f, s.Pkg.Name+"."+s.Name)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case FTypeId:
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtUnsigned != 0 {
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(f, s.Pkg.Name+"."+s.Name) // dcommontype, typehash
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(f, s.Pkg.Prefix+"."+s.Name) // (methodsym), typesym, weaksym
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtByte != 0 {
|
2015-02-27 22:44:15 +00:00
|
|
|
// FmtByte (hh) implies FmtShort (h)
|
2015-02-13 14:40:36 -05:00
|
|
|
// skip leading "type." in method name
|
2016-08-24 23:02:08 -07:00
|
|
|
name := s.Name
|
|
|
|
|
if i := strings.LastIndex(name, "."); i >= 0 {
|
|
|
|
|
name = name[i+1:]
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-16 12:55:17 -07:00
|
|
|
if fmtmode == FDbg {
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprintf(f, "@%q.%s", s.Pkg.Path, name)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(f, name)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(f, s.Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var basicnames = []string{
|
|
|
|
|
TINT: "int",
|
|
|
|
|
TUINT: "uint",
|
|
|
|
|
TINT8: "int8",
|
|
|
|
|
TUINT8: "uint8",
|
|
|
|
|
TINT16: "int16",
|
|
|
|
|
TUINT16: "uint16",
|
|
|
|
|
TINT32: "int32",
|
|
|
|
|
TUINT32: "uint32",
|
|
|
|
|
TINT64: "int64",
|
|
|
|
|
TUINT64: "uint64",
|
|
|
|
|
TUINTPTR: "uintptr",
|
|
|
|
|
TFLOAT32: "float32",
|
|
|
|
|
TFLOAT64: "float64",
|
|
|
|
|
TCOMPLEX64: "complex64",
|
|
|
|
|
TCOMPLEX128: "complex128",
|
|
|
|
|
TBOOL: "bool",
|
|
|
|
|
TANY: "any",
|
|
|
|
|
TSTRING: "string",
|
|
|
|
|
TNIL: "nil",
|
|
|
|
|
TIDEAL: "untyped number",
|
|
|
|
|
TBLANK: "blank",
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-31 10:32:40 -07:00
|
|
|
func (t *Type) typefmt(s fmt.State, flag FmtFlag) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "<T>")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t == bytetype || t == runetype {
|
|
|
|
|
// in %-T mode collapse rune and byte with their originals.
|
|
|
|
|
if fmtmode != FTypeId {
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, "%S", t.Sym)
|
2016-08-31 10:32:40 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
t = Types[t.Etype]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t == errortype {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "error")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unless the 'l' flag was specified, if the type has a name, just print that name.
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtLong == 0 && t.Sym != nil && t != Types[t.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch fmtmode {
|
|
|
|
|
case FTypeId:
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtShort != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
if t.Vargen != 0 {
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, "%S·%d", t.Sym, t.Vargen)
|
2016-08-31 10:32:40 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, "%S", t.Sym)
|
2016-08-31 10:32:40 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtUnsigned != 0 {
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprintf(s, "% v", t.Sym)
|
2016-08-31 10:32:40 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Sym.Pkg == localpkg && t.Vargen != 0 {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprintf(s, "%v·%d", t.Sym, t.Vargen)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(s, t.Sym)
|
2016-08-31 10:32:40 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
|
|
|
|
|
if fmtmode == FErr && (t == idealbool || t == idealstring) {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "untyped ")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, basicnames[t.Etype])
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fmtmode == FDbg {
|
2015-03-12 18:45:30 -04:00
|
|
|
fmtmode = 0
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprintf(s, "%v-", t.Etype)
|
|
|
|
|
t.typefmt(s, flag)
|
2015-03-12 18:45:30 -04:00
|
|
|
fmtmode = FDbg
|
2016-08-31 10:32:40 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch t.Etype {
|
2015-04-01 09:38:44 -07:00
|
|
|
case TPTR32, TPTR64:
|
2016-03-15 13:06:58 -07:00
|
|
|
if fmtmode == FTypeId && (flag&FmtShort != 0) {
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, "*%S", t.Elem())
|
2016-08-31 10:32:40 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "*"+t.Elem().String())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TARRAY:
|
2016-03-27 17:57:42 -07:00
|
|
|
if t.isDDDArray() {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "[...]"+t.Elem().String())
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprintf(s, "[%d]%v", t.NumElem(), t.Elem())
|
2016-04-18 14:02:08 -07:00
|
|
|
|
|
|
|
|
case TSLICE:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "[]"+t.Elem().String())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TCHAN:
|
2016-04-02 16:26:30 -07:00
|
|
|
switch t.ChanDir() {
|
2015-02-13 14:40:36 -05:00
|
|
|
case Crecv:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "<-chan "+t.Elem().String())
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case Csend:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "chan<- "+t.Elem().String())
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-04-02 16:26:30 -07:00
|
|
|
if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym == nil && t.Elem().ChanDir() == Crecv {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "chan ("+t.Elem().String()+")")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "chan "+t.Elem().String())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TMAP:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "map["+t.Key().String()+"]"+t.Val().String())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TINTER:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "interface {")
|
2016-03-17 00:44:07 -07:00
|
|
|
for i, f := range t.Fields().Slice() {
|
|
|
|
|
if i != 0 {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, ";")
|
2016-03-17 00:44:07 -07:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, " ")
|
2015-08-29 11:30:10 +00:00
|
|
|
switch {
|
2016-03-17 00:44:07 -07:00
|
|
|
case f.Sym == nil:
|
2015-08-29 11:30:10 +00:00
|
|
|
// Check first that a symbol is defined for this type.
|
|
|
|
|
// Wrong interface definitions may have types lacking a symbol.
|
|
|
|
|
break
|
2016-03-17 00:44:07 -07:00
|
|
|
case exportname(f.Sym.Name):
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, "%S", f.Sym)
|
2015-08-29 11:30:10 +00:00
|
|
|
default:
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprintf(s, "% v", f.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, "%S", f.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-17 00:44:07 -07:00
|
|
|
if t.NumFields() != 0 {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, " ")
|
2015-03-12 18:45:30 -04:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "}")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TFUNC:
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtShort != 0 {
|
2015-03-12 18:45:30 -04:00
|
|
|
// no leading func
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-03-17 01:47:16 -07:00
|
|
|
if t.Recv() != nil {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprintf(s, "method %v ", t.Recvs())
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "func")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprintf(s, "%v", t.Params())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-17 01:47:16 -07:00
|
|
|
switch t.Results().NumFields() {
|
2015-02-13 14:40:36 -05:00
|
|
|
case 0:
|
2016-08-16 12:55:17 -07:00
|
|
|
// nothing to do
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case 1:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprintf(s, " %v", t.Results().Field(0).Type) // struct->field->field's type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
default:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprintf(s, " %v", t.Results())
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TSTRUCT:
|
2016-04-01 20:11:30 -07:00
|
|
|
if m := t.StructType().Map; m != nil {
|
|
|
|
|
mt := m.MapType()
|
2015-03-12 18:45:30 -04:00
|
|
|
// Format the bucket struct for map[x]y as map.bucket[x]y.
|
|
|
|
|
// This avoids a recursive print that generates very long names.
|
2016-04-01 20:11:30 -07:00
|
|
|
if mt.Bucket == t {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "map.bucket["+m.Key().String()+"]"+m.Val().String())
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-04-01 20:11:30 -07:00
|
|
|
if mt.Hmap == t {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "map.hdr["+m.Key().String()+"]"+m.Val().String())
|
|
|
|
|
return
|
2016-02-23 07:46:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-04-01 20:11:30 -07:00
|
|
|
if mt.Hiter == t {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "map.iter["+m.Key().String()+"]"+m.Val().String())
|
|
|
|
|
return
|
2016-02-23 07:46:01 +00:00
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("unknown internal map type")
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-05 16:44:07 -07:00
|
|
|
if t.IsFuncArgStruct() {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "(")
|
2016-03-17 00:44:07 -07:00
|
|
|
var flag1 FmtFlag
|
2015-02-13 14:40:36 -05:00
|
|
|
if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
|
2016-03-17 00:44:07 -07:00
|
|
|
flag1 = FmtShort
|
|
|
|
|
}
|
|
|
|
|
for i, f := range t.Fields().Slice() {
|
|
|
|
|
if i != 0 {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, ", ")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, Fldconv(f, flag1))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, ")")
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "struct {")
|
2016-03-17 00:44:07 -07:00
|
|
|
for i, f := range t.Fields().Slice() {
|
|
|
|
|
if i != 0 {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, ";")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, " ")
|
|
|
|
|
fmt.Fprint(s, Fldconv(f, FmtLong))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-17 00:44:07 -07:00
|
|
|
if t.NumFields() != 0 {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, " ")
|
2015-03-12 18:45:30 -04:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "}")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TFORW:
|
|
|
|
|
if t.Sym != nil {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "undefined "+t.Sym.String())
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "undefined")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TUNSAFEPTR:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "unsafe.Pointer")
|
2016-03-31 14:46:04 -07:00
|
|
|
|
|
|
|
|
case TDDDFIELD:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprintf(s, "%v <%v> %v", t.Etype, t.Sym, t.DDDField())
|
2016-04-08 13:33:43 -04:00
|
|
|
|
|
|
|
|
case Txxx:
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "Txxx")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-08-31 17:49:49 -07:00
|
|
|
default:
|
|
|
|
|
// Don't know how to handle - fall back to detailed prints.
|
|
|
|
|
fmt.Fprintf(s, "%v <%v> %v", t.Etype, t.Sym, t.Elem())
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Statements which may be rendered with a simplestmt as init.
|
2015-09-24 23:21:18 +02:00
|
|
|
func stmtwithinit(op Op) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch op {
|
2015-04-01 09:38:44 -07:00
|
|
|
case OIF, OFOR, OSWITCH:
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-31 15:32:35 -07:00
|
|
|
func (n *Node) stmtfmt(s fmt.State) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// some statements allow for an init, but at most one,
|
|
|
|
|
// but we may have an arbitrary number added, eg by typecheck
|
2016-03-01 23:21:55 +00:00
|
|
|
// and inlining. If it doesn't fit the syntax, emit an enclosing
|
2015-02-13 14:40:36 -05:00
|
|
|
// block starting with the init statements.
|
|
|
|
|
|
|
|
|
|
// if we can just say "for" n->ninit; ... then do so
|
2016-03-08 15:10:26 -08:00
|
|
|
simpleinit := n.Ninit.Len() == 1 && n.Ninit.First().Ninit.Len() == 0 && stmtwithinit(n.Op)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// otherwise, print the inits as separate statements
|
2016-03-08 15:10:26 -08:00
|
|
|
complexinit := n.Ninit.Len() != 0 && !simpleinit && (fmtmode != FErr)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
|
2015-09-24 23:21:18 +02:00
|
|
|
extrablock := complexinit && stmtwithinit(n.Op)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if extrablock {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, "{")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if complexinit {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, " %v; ", n.Ninit)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch n.Op {
|
|
|
|
|
case ODCL:
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "var %v %v", n.Left.Sym, n.Left.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case ODCLFIELD:
|
|
|
|
|
if n.Left != nil {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v %v", n.Left, n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v", n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-10-22 10:04:23 -07:00
|
|
|
// Don't export "v = <N>" initializing statements, hope they're always
|
2016-03-18 17:21:32 -07:00
|
|
|
// preceded by the DCL which will be re-parsed and typechecked to reproduce
|
2015-02-13 14:40:36 -05:00
|
|
|
// the "v = <N>" again.
|
cmd/internal/gc: emit write barriers at lower level
This is primarily preparation for inlining, not an optimization by itself,
but it still helps some.
name old new delta
BenchmarkBinaryTree17 18.2s × (0.99,1.01) 17.9s × (0.99,1.01) -1.57%
BenchmarkFannkuch11 4.44s × (1.00,1.00) 4.42s × (1.00,1.00) -0.40%
BenchmarkFmtFprintfEmpty 119ns × (0.95,1.02) 118ns × (0.96,1.02) ~
BenchmarkFmtFprintfString 501ns × (0.99,1.02) 486ns × (0.99,1.01) -2.89%
BenchmarkFmtFprintfInt 474ns × (0.99,1.00) 457ns × (0.99,1.01) -3.59%
BenchmarkFmtFprintfIntInt 792ns × (1.00,1.00) 768ns × (1.00,1.01) -3.03%
BenchmarkFmtFprintfPrefixedInt 574ns × (1.00,1.01) 584ns × (0.99,1.03) +1.83%
BenchmarkFmtFprintfFloat 749ns × (1.00,1.00) 739ns × (0.99,1.00) -1.34%
BenchmarkFmtManyArgs 2.94µs × (1.00,1.01) 2.77µs × (1.00,1.00) -5.76%
BenchmarkGobDecode 39.5ms × (0.99,1.01) 39.3ms × (0.99,1.01) ~
BenchmarkGobEncode 39.4ms × (1.00,1.01) 39.4ms × (0.99,1.00) ~
BenchmarkGzip 658ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 142ms × (1.00,1.00) 142ms × (1.00,1.00) +0.22%
BenchmarkHTTPClientServer 134µs × (0.99,1.01) 133µs × (0.98,1.01) ~
BenchmarkJSONEncode 57.1ms × (0.99,1.01) 56.5ms × (0.99,1.01) ~
BenchmarkJSONDecode 141ms × (1.00,1.00) 143ms × (1.00,1.00) +1.09%
BenchmarkMandelbrot200 6.01ms × (1.00,1.00) 6.01ms × (1.00,1.00) ~
BenchmarkGoParse 10.1ms × (0.91,1.09) 9.6ms × (0.94,1.07) ~
BenchmarkRegexpMatchEasy0_32 207ns × (1.00,1.01) 210ns × (1.00,1.00) +1.45%
BenchmarkRegexpMatchEasy0_1K 592ns × (0.99,1.00) 596ns × (0.99,1.01) +0.68%
BenchmarkRegexpMatchEasy1_32 184ns × (0.99,1.01) 184ns × (0.99,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.00) 1.01µs × (0.99,1.01) ~
BenchmarkRegexpMatchMedium_32 327ns × (0.99,1.00) 327ns × (1.00,1.01) ~
BenchmarkRegexpMatchMedium_1K 92.5µs × (1.00,1.00) 93.0µs × (1.00,1.02) +0.48%
BenchmarkRegexpMatchHard_32 4.79µs × (0.95,1.00) 4.76µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.00) 136µs × (1.00,1.01) ~
BenchmarkRevcomp 900ms × (0.99,1.01) 892ms × (1.00,1.01) ~
BenchmarkTemplate 170ms × (0.99,1.01) 175ms × (0.99,1.00) +2.95%
BenchmarkTimeParse 645ns × (1.00,1.00) 638ns × (1.00,1.00) -1.16%
BenchmarkTimeFormat 740ns × (1.00,1.00) 772ns × (1.00,1.00) +4.39%
Change-Id: I0be905e32791e0cb70ff01f169c4b309a971d981
Reviewed-on: https://go-review.googlesource.com/9159
Reviewed-by: Rick Hudson <rlh@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2015-04-17 00:25:10 -04:00
|
|
|
case OAS, OASWB:
|
2015-04-02 19:58:37 -07:00
|
|
|
if n.Colas && !complexinit {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v := %v", n.Left, n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v = %v", n.Left, n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OASOP:
|
2015-03-06 21:18:41 +11:00
|
|
|
if n.Implicit {
|
2015-09-24 23:21:18 +02:00
|
|
|
if Op(n.Etype) == OADD {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v++", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v--", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v %#v= %v", n.Left, Op(n.Etype), n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OAS2:
|
2015-04-02 19:58:37 -07:00
|
|
|
if n.Colas && !complexinit {
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "%.v := %.v", n.List, n.Rlist)
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "%.v = %.v", n.List, n.Rlist)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case ORETURN:
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "return %.v", n.List)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case ORETJMP:
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "retjmp %v", n.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OPROC:
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "go %v", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case ODEFER:
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "defer %v", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OIF:
|
2015-02-17 22:13:49 -05:00
|
|
|
if simpleinit {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "if %v; %v { %v }", n.Ninit.First(), n.Left, n.Nbody)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "if %v { %v }", n.Left, n.Nbody)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-08 15:10:26 -08:00
|
|
|
if n.Rlist.Len() != 0 {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, " else { %v }", n.Rlist)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OFOR:
|
|
|
|
|
if fmtmode == FErr { // TODO maybe only if FmtShort, same below
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, "for loop")
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, "for")
|
2015-02-17 22:13:49 -05:00
|
|
|
if simpleinit {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, " %v;", n.Ninit.First())
|
2015-05-22 01:16:52 -04:00
|
|
|
} else if n.Right != nil {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, " ;")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-05-26 21:30:20 -04:00
|
|
|
if n.Left != nil {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, " %v", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-05-22 01:16:52 -04:00
|
|
|
if n.Right != nil {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "; %v", n.Right)
|
2015-02-17 22:13:49 -05:00
|
|
|
} else if simpleinit {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, ";")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, " { %v }", n.Nbody)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case ORANGE:
|
|
|
|
|
if fmtmode == FErr {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, "for loop")
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 15:10:26 -08:00
|
|
|
if n.List.Len() == 0 {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "for range %v { %v }", n.Right, n.Nbody)
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "for %.v = range %v { %v }", n.List, n.Right, n.Nbody)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OSELECT, OSWITCH:
|
2015-02-13 14:40:36 -05:00
|
|
|
if fmtmode == FErr {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v statement", n.Op)
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, n.Op.GoString()) // %#v
|
2015-02-17 22:13:49 -05:00
|
|
|
if simpleinit {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, " %v;", n.Ninit.First())
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-26 21:30:20 -04:00
|
|
|
if n.Left != nil {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, " %v ", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, " { %v }", n.List)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-05-25 14:08:13 -07:00
|
|
|
case OXCASE:
|
2016-03-08 15:10:26 -08:00
|
|
|
if n.List.Len() != 0 {
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "case %.v", n.List)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, "default")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, ": %v", n.Nbody)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-05-25 14:08:13 -07:00
|
|
|
case OCASE:
|
cmd/compile: recognize integer ranges in switch statements
Consider a switch statement like:
switch x {
case 1:
// ...
case 2, 3, 4, 5, 6:
// ...
case 5:
// ...
}
Prior to this CL, the generated code treated
2, 3, 4, 5, and 6 independently in a binary search.
With this CL, the generated code checks whether
2 <= x && x <= 6.
walkinrange then optimizes that range check
into a single unsigned comparison.
Experiments suggest that the best min range size
is 2, using binary size as a proxy for optimization.
Binary sizes before/after this CL:
cmd/compile: 14209728 / 14165360
cmd/go: 9543100 / 9539004
Change-Id: If2f7fb97ca80468fa70351ef540866200c4c996c
Reviewed-on: https://go-review.googlesource.com/26770
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2016-06-17 16:27:23 -07:00
|
|
|
switch {
|
|
|
|
|
case n.Left != nil:
|
|
|
|
|
// single element
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "case %v", n.Left)
|
cmd/compile: recognize integer ranges in switch statements
Consider a switch statement like:
switch x {
case 1:
// ...
case 2, 3, 4, 5, 6:
// ...
case 5:
// ...
}
Prior to this CL, the generated code treated
2, 3, 4, 5, and 6 independently in a binary search.
With this CL, the generated code checks whether
2 <= x && x <= 6.
walkinrange then optimizes that range check
into a single unsigned comparison.
Experiments suggest that the best min range size
is 2, using binary size as a proxy for optimization.
Binary sizes before/after this CL:
cmd/compile: 14209728 / 14165360
cmd/go: 9543100 / 9539004
Change-Id: If2f7fb97ca80468fa70351ef540866200c4c996c
Reviewed-on: https://go-review.googlesource.com/26770
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2016-06-17 16:27:23 -07:00
|
|
|
case n.List.Len() > 0:
|
|
|
|
|
// range
|
|
|
|
|
if n.List.Len() != 2 {
|
2016-09-02 14:21:57 -07:00
|
|
|
Fatalf("bad OCASE list length %d", n.List.Len())
|
cmd/compile: recognize integer ranges in switch statements
Consider a switch statement like:
switch x {
case 1:
// ...
case 2, 3, 4, 5, 6:
// ...
case 5:
// ...
}
Prior to this CL, the generated code treated
2, 3, 4, 5, and 6 independently in a binary search.
With this CL, the generated code checks whether
2 <= x && x <= 6.
walkinrange then optimizes that range check
into a single unsigned comparison.
Experiments suggest that the best min range size
is 2, using binary size as a proxy for optimization.
Binary sizes before/after this CL:
cmd/compile: 14209728 / 14165360
cmd/go: 9543100 / 9539004
Change-Id: If2f7fb97ca80468fa70351ef540866200c4c996c
Reviewed-on: https://go-review.googlesource.com/26770
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2016-06-17 16:27:23 -07:00
|
|
|
}
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "case %v..%v", n.List.First(), n.List.Second())
|
cmd/compile: recognize integer ranges in switch statements
Consider a switch statement like:
switch x {
case 1:
// ...
case 2, 3, 4, 5, 6:
// ...
case 5:
// ...
}
Prior to this CL, the generated code treated
2, 3, 4, 5, and 6 independently in a binary search.
With this CL, the generated code checks whether
2 <= x && x <= 6.
walkinrange then optimizes that range check
into a single unsigned comparison.
Experiments suggest that the best min range size
is 2, using binary size as a proxy for optimization.
Binary sizes before/after this CL:
cmd/compile: 14209728 / 14165360
cmd/go: 9543100 / 9539004
Change-Id: If2f7fb97ca80468fa70351ef540866200c4c996c
Reviewed-on: https://go-review.googlesource.com/26770
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2016-06-17 16:27:23 -07:00
|
|
|
default:
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, "default")
|
2016-05-25 14:08:13 -07:00
|
|
|
}
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, ": %v", n.Nbody)
|
2016-05-25 14:08:13 -07:00
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
case OBREAK,
|
|
|
|
|
OCONTINUE,
|
|
|
|
|
OGOTO,
|
|
|
|
|
OFALL,
|
|
|
|
|
OXFALL:
|
|
|
|
|
if n.Left != nil {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%#v %v", n.Op, n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, n.Op.GoString()) // %#v
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OEMPTY:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case OLABEL:
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v: ", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if extrablock {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, "}")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var opprec = []int{
|
|
|
|
|
OAPPEND: 8,
|
|
|
|
|
OARRAYBYTESTR: 8,
|
|
|
|
|
OARRAYLIT: 8,
|
2016-06-19 07:20:28 -07:00
|
|
|
OSLICELIT: 8,
|
2015-02-13 14:40:36 -05:00
|
|
|
OARRAYRUNESTR: 8,
|
|
|
|
|
OCALLFUNC: 8,
|
|
|
|
|
OCALLINTER: 8,
|
|
|
|
|
OCALLMETH: 8,
|
|
|
|
|
OCALL: 8,
|
|
|
|
|
OCAP: 8,
|
|
|
|
|
OCLOSE: 8,
|
|
|
|
|
OCONVIFACE: 8,
|
|
|
|
|
OCONVNOP: 8,
|
|
|
|
|
OCONV: 8,
|
|
|
|
|
OCOPY: 8,
|
|
|
|
|
ODELETE: 8,
|
2015-04-03 12:23:28 -04:00
|
|
|
OGETG: 8,
|
2015-02-13 14:40:36 -05:00
|
|
|
OLEN: 8,
|
|
|
|
|
OLITERAL: 8,
|
|
|
|
|
OMAKESLICE: 8,
|
|
|
|
|
OMAKE: 8,
|
|
|
|
|
OMAPLIT: 8,
|
|
|
|
|
ONAME: 8,
|
|
|
|
|
ONEW: 8,
|
|
|
|
|
ONONAME: 8,
|
|
|
|
|
OPACK: 8,
|
|
|
|
|
OPANIC: 8,
|
|
|
|
|
OPAREN: 8,
|
|
|
|
|
OPRINTN: 8,
|
|
|
|
|
OPRINT: 8,
|
|
|
|
|
ORUNESTR: 8,
|
|
|
|
|
OSTRARRAYBYTE: 8,
|
|
|
|
|
OSTRARRAYRUNE: 8,
|
|
|
|
|
OSTRUCTLIT: 8,
|
|
|
|
|
OTARRAY: 8,
|
|
|
|
|
OTCHAN: 8,
|
|
|
|
|
OTFUNC: 8,
|
|
|
|
|
OTINTER: 8,
|
|
|
|
|
OTMAP: 8,
|
|
|
|
|
OTSTRUCT: 8,
|
|
|
|
|
OINDEXMAP: 8,
|
|
|
|
|
OINDEX: 8,
|
|
|
|
|
OSLICE: 8,
|
|
|
|
|
OSLICESTR: 8,
|
|
|
|
|
OSLICEARR: 8,
|
|
|
|
|
OSLICE3: 8,
|
|
|
|
|
OSLICE3ARR: 8,
|
|
|
|
|
ODOTINTER: 8,
|
|
|
|
|
ODOTMETH: 8,
|
|
|
|
|
ODOTPTR: 8,
|
|
|
|
|
ODOTTYPE2: 8,
|
|
|
|
|
ODOTTYPE: 8,
|
|
|
|
|
ODOT: 8,
|
|
|
|
|
OXDOT: 8,
|
|
|
|
|
OCALLPART: 8,
|
|
|
|
|
OPLUS: 7,
|
|
|
|
|
ONOT: 7,
|
|
|
|
|
OCOM: 7,
|
|
|
|
|
OMINUS: 7,
|
|
|
|
|
OADDR: 7,
|
|
|
|
|
OIND: 7,
|
|
|
|
|
ORECV: 7,
|
|
|
|
|
OMUL: 6,
|
|
|
|
|
ODIV: 6,
|
|
|
|
|
OMOD: 6,
|
|
|
|
|
OLSH: 6,
|
|
|
|
|
ORSH: 6,
|
|
|
|
|
OAND: 6,
|
|
|
|
|
OANDNOT: 6,
|
|
|
|
|
OADD: 5,
|
|
|
|
|
OSUB: 5,
|
|
|
|
|
OOR: 5,
|
|
|
|
|
OXOR: 5,
|
|
|
|
|
OEQ: 4,
|
|
|
|
|
OLT: 4,
|
|
|
|
|
OLE: 4,
|
|
|
|
|
OGE: 4,
|
|
|
|
|
OGT: 4,
|
|
|
|
|
ONE: 4,
|
|
|
|
|
OCMPSTR: 4,
|
|
|
|
|
OCMPIFACE: 4,
|
|
|
|
|
OSEND: 3,
|
|
|
|
|
OANDAND: 2,
|
|
|
|
|
OOROR: 1,
|
2015-02-20 13:54:45 -05:00
|
|
|
// Statements handled by stmtfmt
|
|
|
|
|
OAS: -1,
|
2015-02-13 14:40:36 -05:00
|
|
|
OAS2: -1,
|
|
|
|
|
OAS2DOTTYPE: -1,
|
|
|
|
|
OAS2FUNC: -1,
|
|
|
|
|
OAS2MAPR: -1,
|
|
|
|
|
OAS2RECV: -1,
|
|
|
|
|
OASOP: -1,
|
|
|
|
|
OBREAK: -1,
|
|
|
|
|
OCASE: -1,
|
|
|
|
|
OCONTINUE: -1,
|
|
|
|
|
ODCL: -1,
|
|
|
|
|
ODCLFIELD: -1,
|
|
|
|
|
ODEFER: -1,
|
|
|
|
|
OEMPTY: -1,
|
|
|
|
|
OFALL: -1,
|
|
|
|
|
OFOR: -1,
|
|
|
|
|
OGOTO: -1,
|
|
|
|
|
OIF: -1,
|
|
|
|
|
OLABEL: -1,
|
|
|
|
|
OPROC: -1,
|
|
|
|
|
ORANGE: -1,
|
|
|
|
|
ORETURN: -1,
|
|
|
|
|
OSELECT: -1,
|
|
|
|
|
OSWITCH: -1,
|
|
|
|
|
OXCASE: -1,
|
|
|
|
|
OXFALL: -1,
|
|
|
|
|
OEND: 0,
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-31 16:02:36 -07:00
|
|
|
func (n *Node) exprfmt(s fmt.State, prec int) {
|
2015-03-06 21:18:41 +11:00
|
|
|
for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
n = n.Left
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n == nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, "<N>")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
nprec := opprec[n.Op]
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Op == OTYPE && n.Sym != nil {
|
|
|
|
|
nprec = 8
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if prec > nprec {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "(%v)", n)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch n.Op {
|
|
|
|
|
case OPAREN:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "(%v)", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case ODDDARG:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, "... argument")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OREGISTER:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, obj.Rconv(int(n.Reg)))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OLITERAL: // this is a bit of a mess
|
2015-03-03 23:28:00 -05:00
|
|
|
if fmtmode == FErr {
|
|
|
|
|
if n.Orig != nil && n.Orig != n {
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Orig.exprfmt(s, prec)
|
|
|
|
|
return
|
2015-03-03 23:28:00 -05:00
|
|
|
}
|
|
|
|
|
if n.Sym != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, n.Sym.String())
|
|
|
|
|
return
|
2015-03-03 23:28:00 -05:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Orig.exprfmt(s, prec)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-12-14 14:07:21 -05:00
|
|
|
if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != idealbool && n.Type != idealstring {
|
2015-02-13 14:40:36 -05:00
|
|
|
// Need parens when type begins with what might
|
|
|
|
|
// be misinterpreted as a unary operator: * or <-.
|
2016-04-02 16:26:30 -07:00
|
|
|
if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == Crecv) {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "(%v)(%v)", n.Type, n.Val())
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%v(%v)", n.Type, n.Val())
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, "%v", n.Val())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-10-22 10:04:23 -07:00
|
|
|
// Special case: name used as local variable in export.
|
2015-02-13 14:40:36 -05:00
|
|
|
// _ becomes ~b%d internally; print as _ for export
|
|
|
|
|
case ONAME:
|
2016-08-16 12:55:17 -07:00
|
|
|
if fmtmode == FErr && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, "_")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
fallthrough
|
2015-04-01 09:38:44 -07:00
|
|
|
case OPACK, ONONAME:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, n.Sym.String())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OTYPE:
|
|
|
|
|
if n.Type == nil && n.Sym != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, n.Sym.String())
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%v", n.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OTARRAY:
|
|
|
|
|
if n.Left != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "[]%v", n.Left)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "[]%v", n.Right) // happens before typecheck
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OTMAP:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "map[%v]%v", n.Left, n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OTCHAN:
|
2016-04-03 22:58:10 +00:00
|
|
|
switch ChanDir(n.Etype) {
|
2015-02-13 14:40:36 -05:00
|
|
|
case Crecv:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "<-chan %v", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case Csend:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "chan<- %v", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
default:
|
2016-04-03 22:58:10 +00:00
|
|
|
if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && ChanDir(n.Left.Etype) == Crecv {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "chan (%v)", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "chan %v", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OTSTRUCT:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, "<struct>")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OTINTER:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, "<inter>")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OTFUNC:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, "<func>")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OCLOSURE:
|
|
|
|
|
if fmtmode == FErr {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, "func literal")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-04-24 13:50:26 -07:00
|
|
|
if n.Nbody.Len() != 0 {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%v { %v }", n.Type, n.Nbody)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%v { %v }", n.Type, n.Func.Closure.Nbody)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OCOMPLIT:
|
2016-03-30 15:09:25 -07:00
|
|
|
ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && n.Right.Type.IsPtr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if fmtmode == FErr {
|
2015-03-06 21:18:41 +11:00
|
|
|
if n.Right != nil && n.Right.Type != nil && !n.Implicit {
|
2015-02-17 22:13:49 -05:00
|
|
|
if ptrlit {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "&%v literal", n.Right.Type.Elem())
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%v literal", n.Right.Type)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, "composite literal")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "(%v{ %.v })", n.Right, n.List)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OPTRLIT:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "&%v", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-06-19 07:20:28 -07:00
|
|
|
case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
|
2015-02-13 14:40:36 -05:00
|
|
|
if fmtmode == FErr {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%v literal", n.Type)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "(%v{ %.v })", n.Type, n.List)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OKEY:
|
|
|
|
|
if n.Left != nil && n.Right != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%v:%v", n.Left, n.Right)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Left == nil && n.Right != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, ":%v", n.Right)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Left != nil && n.Right == nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%v:", n.Left)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, ":")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
case OCALLPART:
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Left.exprfmt(s, nprec)
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Right == nil || n.Right.Sym == nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, ".<nil>")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, ".%0S", n.Right.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Left.exprfmt(s, nprec)
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
if n.Sym == nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, ".<nil>")
|
|
|
|
|
return
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
}
|
2016-09-09 21:08:46 -07:00
|
|
|
fmt.Fprintf(s, ".%0S", n.Sym)
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case ODOTTYPE, ODOTTYPE2:
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Left.exprfmt(s, nprec)
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Right != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, ".(%v)", n.Right)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, ".(%v)", n.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-04-21 11:55:33 -07:00
|
|
|
case OINDEX, OINDEXMAP:
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Left.exprfmt(s, nprec)
|
|
|
|
|
fmt.Fprintf(s, "[%v]", n.Right)
|
2016-04-21 11:55:33 -07:00
|
|
|
|
|
|
|
|
case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Left.exprfmt(s, nprec)
|
|
|
|
|
fmt.Fprint(s, "[")
|
2016-04-21 11:55:33 -07:00
|
|
|
low, high, max := n.SliceBounds()
|
|
|
|
|
if low != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, low.String())
|
2016-04-21 11:55:33 -07:00
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, ":")
|
2016-04-21 11:55:33 -07:00
|
|
|
if high != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, high.String())
|
2016-04-21 11:55:33 -07:00
|
|
|
}
|
|
|
|
|
if n.Op.IsSlice3() {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, ":")
|
2016-04-21 11:55:33 -07:00
|
|
|
if max != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, max.String())
|
2016-04-21 11:55:33 -07:00
|
|
|
}
|
|
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, "]")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OCOPY, OCOMPLEX:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OCONV,
|
|
|
|
|
OCONVIFACE,
|
|
|
|
|
OCONVNOP,
|
|
|
|
|
OARRAYBYTESTR,
|
|
|
|
|
OARRAYRUNESTR,
|
|
|
|
|
OSTRARRAYBYTE,
|
|
|
|
|
OSTRARRAYRUNE,
|
|
|
|
|
ORUNESTR:
|
|
|
|
|
if n.Type == nil || n.Type.Sym == nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "(%v)(%v)", n.Type, n.Left)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n.Left != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%v(%v)", n.Type, n.Left)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "%v(%.v)", n.Type, n.List)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OREAL,
|
|
|
|
|
OIMAG,
|
|
|
|
|
OAPPEND,
|
|
|
|
|
OCAP,
|
|
|
|
|
OCLOSE,
|
|
|
|
|
ODELETE,
|
|
|
|
|
OLEN,
|
|
|
|
|
OMAKE,
|
|
|
|
|
ONEW,
|
|
|
|
|
OPANIC,
|
|
|
|
|
ORECOVER,
|
|
|
|
|
OPRINT,
|
|
|
|
|
OPRINTN:
|
|
|
|
|
if n.Left != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "%#v(%v)", n.Op, n.Left)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-09 16:24:07 +11:00
|
|
|
if n.Isddd {
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "%#v(%.v...)", n.Op, n.List)
|
2016-08-31 16:02:36 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "%#v(%.v)", n.Op, n.List)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-03 12:23:28 -04:00
|
|
|
case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Left.exprfmt(s, nprec)
|
2015-03-09 16:24:07 +11:00
|
|
|
if n.Isddd {
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "(%.v...)", n.List)
|
2016-08-31 16:02:36 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "(%.v)", n.List)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OMAKEMAP, OMAKECHAN, OMAKESLICE:
|
2016-03-08 15:10:26 -08:00
|
|
|
if n.List.Len() != 0 { // pre-typecheck
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprintf(s, "make(%v, %.v)", n.Type, n.List)
|
2016-08-31 16:02:36 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n.Right != nil {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "make(%v, %v, %v)", n.Type, n.Left, n.Right)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-04-01 13:36:24 -07:00
|
|
|
if n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()) {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "make(%v, %v)", n.Type, n.Left)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, "make(%v)", n.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// Unary
|
|
|
|
|
case OPLUS,
|
|
|
|
|
OMINUS,
|
|
|
|
|
OADDR,
|
|
|
|
|
OCOM,
|
|
|
|
|
OIND,
|
|
|
|
|
ONOT,
|
|
|
|
|
ORECV:
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, n.Op.GoString()) // %#v
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Left.Op == n.Op {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, " ")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Left.exprfmt(s, nprec+1)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// Binary
|
|
|
|
|
case OADD,
|
|
|
|
|
OAND,
|
|
|
|
|
OANDAND,
|
|
|
|
|
OANDNOT,
|
|
|
|
|
ODIV,
|
|
|
|
|
OEQ,
|
|
|
|
|
OGE,
|
|
|
|
|
OGT,
|
|
|
|
|
OLE,
|
|
|
|
|
OLT,
|
|
|
|
|
OLSH,
|
|
|
|
|
OMOD,
|
|
|
|
|
OMUL,
|
|
|
|
|
ONE,
|
|
|
|
|
OOR,
|
|
|
|
|
OOROR,
|
|
|
|
|
ORSH,
|
|
|
|
|
OSEND,
|
|
|
|
|
OSUB,
|
|
|
|
|
OXOR:
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Left.exprfmt(s, nprec)
|
|
|
|
|
fmt.Fprintf(s, " %#v ", n.Op)
|
|
|
|
|
n.Right.exprfmt(s, nprec+1)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OADDSTR:
|
2016-03-04 13:16:48 -08:00
|
|
|
i := 0
|
2016-03-08 15:10:26 -08:00
|
|
|
for _, n1 := range n.List.Slice() {
|
2016-03-04 13:16:48 -08:00
|
|
|
if i != 0 {
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprint(s, " + ")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 16:02:36 -07:00
|
|
|
n1.exprfmt(s, nprec)
|
2016-03-04 13:16:48 -08:00
|
|
|
i++
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OCMPSTR, OCMPIFACE:
|
2016-08-31 16:02:36 -07:00
|
|
|
n.Left.exprfmt(s, nprec)
|
2015-09-24 23:21:18 +02:00
|
|
|
// TODO(marvin): Fix Node.EType type union.
|
2016-08-31 16:02:36 -07:00
|
|
|
fmt.Fprintf(s, " %#v ", Op(n.Etype))
|
|
|
|
|
n.Right.exprfmt(s, nprec+1)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-08-31 17:49:49 -07:00
|
|
|
default:
|
|
|
|
|
fmt.Fprintf(s, "<node %v>", n.Op)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-31 15:32:35 -07:00
|
|
|
func (n *Node) nodefmt(s fmt.State, flag FmtFlag) {
|
2015-02-23 16:07:24 -05:00
|
|
|
t := n.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// we almost always want the original, except in export mode for literals
|
|
|
|
|
// this saves the importer some work, and avoids us having to redo some
|
|
|
|
|
// special casing for package unsafe
|
2016-08-16 12:55:17 -07:00
|
|
|
if n.Op != OLITERAL && n.Orig != nil {
|
2015-02-13 14:40:36 -05:00
|
|
|
n = n.Orig
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtLong != 0 && t != nil {
|
2015-02-13 14:40:36 -05:00
|
|
|
if t.Etype == TNIL {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprint(s, "nil")
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 15:32:35 -07:00
|
|
|
fmt.Fprintf(s, "%v (type %v)", n, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 15:32:35 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO inlining produces expressions with ninits. we can't print these yet.
|
|
|
|
|
|
|
|
|
|
if opprec[n.Op] < 0 {
|
2016-08-31 15:32:35 -07:00
|
|
|
n.stmtfmt(s)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-31 16:02:36 -07:00
|
|
|
n.exprfmt(s, 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-31 16:07:49 -07:00
|
|
|
func (n *Node) nodedump(s fmt.State, flag FmtFlag) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n == nil {
|
2016-08-31 16:07:49 -07:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
recur := flag&FmtShort == 0
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if recur {
|
2016-08-31 16:07:49 -07:00
|
|
|
indent(s)
|
2016-08-26 16:38:06 -07:00
|
|
|
if dumpdepth > 10 {
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprint(s, "...")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-08 15:10:26 -08:00
|
|
|
if n.Ninit.Len() != 0 {
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v-init%v", n.Op, n.Ninit)
|
|
|
|
|
indent(s)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch n.Op {
|
|
|
|
|
default:
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v%j", n.Op, n)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OREGISTER, OINDREG:
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v-%v%j", n.Op, obj.Rconv(int(n.Reg)), n)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OLITERAL:
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v-%v%j", n.Op, n.Val(), n)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case ONAME, ONONAME:
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Sym != nil {
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v-%v%j", n.Op, n.Sym, n)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v%j", n.Op, n)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-19 12:06:31 -05:00
|
|
|
if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
|
2016-08-31 16:07:49 -07:00
|
|
|
indent(s)
|
|
|
|
|
fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OASOP:
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v-%v%j", n.Op, Op(n.Etype), n)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case OTYPE:
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v %v%j type=%v", n.Op, n.Sym, n, n.Type)
|
2015-05-27 00:44:05 -04:00
|
|
|
if recur && n.Type == nil && n.Name.Param.Ntype != nil {
|
2016-08-31 16:07:49 -07:00
|
|
|
indent(s)
|
|
|
|
|
fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Sym != nil && n.Op != ONAME {
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, " %v", n.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Type != nil {
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, " %v", n.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if recur {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Left != nil {
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v", n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n.Right != nil {
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprintf(s, "%v", n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-08 15:10:26 -08:00
|
|
|
if n.List.Len() != 0 {
|
2016-08-31 16:07:49 -07:00
|
|
|
indent(s)
|
|
|
|
|
fmt.Fprintf(s, "%v-list%v", n.Op, n.List)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-08 15:10:26 -08:00
|
|
|
if n.Rlist.Len() != 0 {
|
2016-08-31 16:07:49 -07:00
|
|
|
indent(s)
|
|
|
|
|
fmt.Fprintf(s, "%v-rlist%v", n.Op, n.Rlist)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-04-24 13:50:26 -07:00
|
|
|
if n.Nbody.Len() != 0 {
|
2016-08-31 16:07:49 -07:00
|
|
|
indent(s)
|
|
|
|
|
fmt.Fprintf(s, "%v-body%v", n.Op, n.Nbody)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 16:51:26 -07:00
|
|
|
func (s *Sym) Format(f fmt.State, verb rune) {
|
|
|
|
|
switch verb {
|
2016-09-09 21:08:46 -07:00
|
|
|
case 'v', 'S':
|
2016-09-08 16:51:26 -07:00
|
|
|
s.sconv(f, fmtFlag(f, verb))
|
2016-08-29 17:56:15 -07:00
|
|
|
|
2016-08-31 14:12:35 -07:00
|
|
|
default:
|
2016-09-08 16:51:26 -07:00
|
|
|
fmt.Fprintf(f, "%%!%c(*Sym=%p)", verb, s)
|
2016-08-31 14:12:35 -07:00
|
|
|
}
|
|
|
|
|
}
|
2016-08-29 17:56:15 -07:00
|
|
|
|
2015-04-17 11:56:29 -04:00
|
|
|
func (s *Sym) String() string {
|
2016-08-31 14:12:35 -07:00
|
|
|
return fmt.Sprint(s)
|
2015-04-17 11:56:29 -04:00
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// Fmt "%S": syms
|
|
|
|
|
// Flags: "%hS" suppresses qualifying with package
|
2016-09-08 16:51:26 -07:00
|
|
|
func (s *Sym) sconv(f fmt.State, flag FmtFlag) {
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtLong != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
panic("linksymfmt")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if s == nil {
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(f, "<S>")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if s.Name == "_" {
|
2016-08-31 14:12:35 -07:00
|
|
|
fmt.Fprint(f, "_")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
sf := flag
|
2016-08-30 11:19:07 -07:00
|
|
|
sm := setfmode(&flag)
|
2016-08-31 14:12:35 -07:00
|
|
|
s.symfmt(f, flag)
|
2015-02-13 14:40:36 -05:00
|
|
|
flag = sf
|
|
|
|
|
fmtmode = sm
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-17 11:56:29 -04:00
|
|
|
func (t *Type) String() string {
|
2016-08-31 10:32:40 -07:00
|
|
|
return fmt.Sprint(t)
|
2015-04-17 11:56:29 -04:00
|
|
|
}
|
|
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
func Fldconv(f *Field, flag FmtFlag) string {
|
2016-03-14 01:20:49 -07:00
|
|
|
if f == nil {
|
|
|
|
|
return "<T>"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sf := flag
|
2016-08-30 11:19:07 -07:00
|
|
|
sm := setfmode(&flag)
|
2016-03-14 01:20:49 -07:00
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
|
2016-03-14 01:20:49 -07:00
|
|
|
fmtpkgpfx++
|
|
|
|
|
}
|
|
|
|
|
if fmtpkgpfx != 0 {
|
2016-03-15 13:06:58 -07:00
|
|
|
flag |= FmtUnsigned
|
2016-03-14 01:20:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var name string
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtShort == 0 {
|
2016-03-14 01:20:49 -07:00
|
|
|
s := f.Sym
|
|
|
|
|
|
|
|
|
|
// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
|
|
|
|
|
// ~r%d is a (formerly) unnamed result.
|
2016-08-16 12:55:17 -07:00
|
|
|
if fmtmode == FErr && f.Nname != nil {
|
2016-03-14 01:20:49 -07:00
|
|
|
if f.Nname.Orig != nil {
|
|
|
|
|
s = f.Nname.Orig.Sym
|
|
|
|
|
if s != nil && s.Name[0] == '~' {
|
|
|
|
|
if s.Name[1] == 'r' { // originally an unnamed result
|
|
|
|
|
s = nil
|
|
|
|
|
} else if s.Name[1] == 'b' { // originally the blank identifier _
|
|
|
|
|
s = Lookup("_")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
s = nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if s != nil && f.Embedded == 0 {
|
2016-05-25 10:01:58 -04:00
|
|
|
if f.Funarg != FunargNone {
|
2016-08-31 15:22:36 -07:00
|
|
|
name = f.Nname.String()
|
2016-03-15 13:06:58 -07:00
|
|
|
} else if flag&FmtLong != 0 {
|
2016-09-09 21:08:46 -07:00
|
|
|
name = fmt.Sprintf("%0S", s)
|
2016-08-25 14:31:50 -04:00
|
|
|
if !exportname(name) && flag&FmtUnsigned == 0 {
|
2016-08-31 14:12:35 -07:00
|
|
|
name = s.String() // qualify non-exported names (used on structs, not on funarg)
|
2016-08-25 14:31:50 -04:00
|
|
|
}
|
2016-03-14 01:20:49 -07:00
|
|
|
} else {
|
2016-08-31 14:12:35 -07:00
|
|
|
name = s.String()
|
2016-03-14 01:20:49 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var typ string
|
|
|
|
|
if f.Isddd {
|
2016-08-31 10:32:40 -07:00
|
|
|
typ = fmt.Sprintf("...%v", f.Type.Elem())
|
2016-03-14 01:20:49 -07:00
|
|
|
} else {
|
2016-08-31 10:32:40 -07:00
|
|
|
typ = fmt.Sprintf("%v", f.Type)
|
2016-03-14 01:20:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str := typ
|
|
|
|
|
if name != "" {
|
|
|
|
|
str = name + " " + typ
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 11:19:07 -07:00
|
|
|
if flag&FmtShort == 0 && f.Funarg == FunargNone && f.Note != "" {
|
2016-04-25 13:24:48 -07:00
|
|
|
str += " " + strconv.Quote(f.Note)
|
2016-03-14 01:20:49 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
|
2016-03-14 01:20:49 -07:00
|
|
|
fmtpkgpfx--
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flag = sf
|
|
|
|
|
fmtmode = sm
|
|
|
|
|
return str
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 16:51:26 -07:00
|
|
|
func (t *Type) Format(s fmt.State, verb rune) {
|
|
|
|
|
switch verb {
|
2016-09-09 21:08:46 -07:00
|
|
|
case 'v', 'S', 'L':
|
2016-09-08 16:51:26 -07:00
|
|
|
t.tconv(s, fmtFlag(s, verb))
|
2016-08-31 10:32:40 -07:00
|
|
|
|
|
|
|
|
default:
|
2016-09-08 16:51:26 -07:00
|
|
|
fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t)
|
2016-08-31 10:32:40 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// Fmt "%T": types.
|
|
|
|
|
// Flags: 'l' print definition, not name
|
|
|
|
|
// 'h' omit 'func' and receiver from function types, short type names
|
|
|
|
|
// 'u' package name, not prefix (FTypeId mode, sticky)
|
2016-09-08 16:51:26 -07:00
|
|
|
func (t *Type) tconv(s fmt.State, flag FmtFlag) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "<T>")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Trecur > 4 {
|
2016-08-31 10:32:40 -07:00
|
|
|
fmt.Fprint(s, "<...>")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Trecur++
|
2015-02-23 16:07:24 -05:00
|
|
|
sf := flag
|
2016-08-30 11:19:07 -07:00
|
|
|
sm := setfmode(&flag)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
|
2015-02-13 14:40:36 -05:00
|
|
|
fmtpkgpfx++
|
|
|
|
|
}
|
|
|
|
|
if fmtpkgpfx != 0 {
|
2016-03-15 13:06:58 -07:00
|
|
|
flag |= FmtUnsigned
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-31 10:32:40 -07:00
|
|
|
t.typefmt(s, flag)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-15 13:06:58 -07:00
|
|
|
if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
|
2015-02-13 14:40:36 -05:00
|
|
|
fmtpkgpfx--
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flag = sf
|
|
|
|
|
fmtmode = sm
|
|
|
|
|
t.Trecur--
|
2016-08-29 17:56:15 -07:00
|
|
|
}
|
|
|
|
|
|
2015-04-17 11:56:29 -04:00
|
|
|
func (n *Node) String() string {
|
2016-08-31 15:22:36 -07:00
|
|
|
return fmt.Sprint(n)
|
2015-04-17 11:56:29 -04:00
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// Fmt '%N': Nodes.
|
|
|
|
|
// Flags: 'l' suffix with "(type %T)" where possible
|
|
|
|
|
// '+h' in debug mode, don't recurse, no multiline output
|
2016-09-08 16:51:26 -07:00
|
|
|
func (n *Node) Nconv(s fmt.State, flag FmtFlag) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n == nil {
|
2016-08-31 15:22:36 -07:00
|
|
|
fmt.Fprint(s, "<N>")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-31 15:22:36 -07:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
sf := flag
|
2016-08-30 11:19:07 -07:00
|
|
|
sm := setfmode(&flag)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
switch fmtmode {
|
2016-08-16 12:55:17 -07:00
|
|
|
case FErr:
|
2016-08-31 15:32:35 -07:00
|
|
|
n.nodefmt(s, flag)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case FDbg:
|
2016-08-26 16:38:06 -07:00
|
|
|
dumpdepth++
|
2016-08-31 16:07:49 -07:00
|
|
|
n.nodedump(s, flag)
|
2016-08-26 16:38:06 -07:00
|
|
|
dumpdepth--
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
default:
|
2016-08-31 14:12:35 -07:00
|
|
|
Fatalf("unhandled %%N mode: %d", fmtmode)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flag = sf
|
|
|
|
|
fmtmode = sm
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 16:51:26 -07:00
|
|
|
func (l Nodes) Format(s fmt.State, verb rune) {
|
|
|
|
|
switch verb {
|
2016-09-09 21:08:46 -07:00
|
|
|
case 'v':
|
2016-09-08 16:51:26 -07:00
|
|
|
l.hconv(s, fmtFlag(s, verb))
|
2016-08-29 17:56:15 -07:00
|
|
|
|
2016-08-31 16:19:50 -07:00
|
|
|
default:
|
2016-09-08 16:51:26 -07:00
|
|
|
fmt.Fprintf(s, "%%!%c(Nodes)", verb)
|
2016-08-31 16:19:50 -07:00
|
|
|
}
|
|
|
|
|
}
|
2016-08-29 17:56:15 -07:00
|
|
|
|
2016-02-27 14:31:33 -08:00
|
|
|
func (n Nodes) String() string {
|
2016-08-31 16:19:50 -07:00
|
|
|
return fmt.Sprint(n)
|
2016-02-27 14:31:33 -08:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 10:00:29 -08:00
|
|
|
// Fmt '%H': Nodes.
|
2015-02-13 14:40:36 -05:00
|
|
|
// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
|
2016-09-08 16:51:26 -07:00
|
|
|
func (l Nodes) hconv(s fmt.State, flag FmtFlag) {
|
2016-03-08 15:10:26 -08:00
|
|
|
if l.Len() == 0 && fmtmode == FDbg {
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprint(s, "<nil>")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
sf := flag
|
2016-08-30 11:19:07 -07:00
|
|
|
sm := setfmode(&flag)
|
2015-02-23 16:07:24 -05:00
|
|
|
sep := "; "
|
2015-02-13 14:40:36 -05:00
|
|
|
if fmtmode == FDbg {
|
|
|
|
|
sep = "\n"
|
2016-03-15 13:06:58 -07:00
|
|
|
} else if flag&FmtComma != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
sep = ", "
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-09 12:39:36 -08:00
|
|
|
for i, n := range l.Slice() {
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprint(s, n)
|
2016-03-09 12:39:36 -08:00
|
|
|
if i+1 < l.Len() {
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Fprint(s, sep)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flag = sf
|
|
|
|
|
fmtmode = sm
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 10:26:20 -08:00
|
|
|
func dumplist(s string, l Nodes) {
|
2016-08-31 16:19:50 -07:00
|
|
|
fmt.Printf("%s%+v\n", s, l)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Dump(s string, n *Node) {
|
2016-08-31 15:22:36 -07:00
|
|
|
fmt.Printf("%s [%p]%+v\n", s, n, n)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-24 21:47:58 -07:00
|
|
|
|
2016-08-31 16:28:18 -07:00
|
|
|
// TODO(gri) make variable local somehow
|
2016-08-26 16:38:06 -07:00
|
|
|
var dumpdepth int
|
|
|
|
|
|
2016-08-31 16:28:18 -07:00
|
|
|
// indent prints indentation to s.
|
2016-08-31 16:07:49 -07:00
|
|
|
func indent(s fmt.State) {
|
|
|
|
|
fmt.Fprint(s, "\n")
|
2016-08-26 16:38:06 -07:00
|
|
|
for i := 0; i < dumpdepth; i++ {
|
2016-08-31 16:07:49 -07:00
|
|
|
fmt.Fprint(s, ". ")
|
2016-08-24 23:02:08 -07:00
|
|
|
}
|
|
|
|
|
}
|