diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index 85f7f92a423..a4d19c39f8d 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -1029,22 +1029,60 @@ func Nod(op Op, nleft, nright Node) Node { func NodAt(pos src.XPos, op Op, nleft, nright Node) Node { var n *node switch op { + case OAS, OSELRECV: + n := NewAssignStmt(pos, nleft, nright) + n.SetOp(op) + return n + case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV, OSELRECV2: + n := NewAssignListStmt(pos, nil, nil) + n.SetOp(op) + return n + case OASOP: + return NewAssignOpStmt(pos, OXXX, nleft, nright) + case OBLOCK: + return NewBlockStmt(pos, nil) + case OBREAK, OCONTINUE, OFALL, OGOTO, ORETJMP: + return NewBranchStmt(pos, op, nil) + case OCASE: + return NewCaseStmt(pos, nil, nil) + case ODCL, ODCLCONST, ODCLTYPE: + return NewDecl(pos, op, nleft) case ODCLFUNC: return NewFunc(pos) + case ODEFER: + return NewDeferStmt(pos, nleft) case ODEREF: return NewStarExpr(pos, nleft) - case OPACK: - return NewPkgName(pos, nil, nil) case OEMPTY: return NewEmptyStmt(pos) - case OBREAK, OCONTINUE, OFALL, OGOTO: - return NewBranchStmt(pos, op, nil) + case OFOR: + return NewForStmt(pos, nil, nleft, nright, nil) + case OGO: + return NewGoStmt(pos, nleft) + case OIF: + return NewIfStmt(pos, nleft, nil, nil) + case OINLMARK: + return NewInlineMarkStmt(pos, types.BADWIDTH) + case OLABEL: + return NewLabelStmt(pos, nil) case OLITERAL, OTYPE, OIOTA: n := newNameAt(pos, nil) n.SetOp(op) return n - case OLABEL: - return NewLabelStmt(pos, nil) + case OPACK: + return NewPkgName(pos, nil, nil) + case ORANGE: + return NewRangeStmt(pos, nil, nright, nil) + case ORETURN: + return NewReturnStmt(pos, nil) + case OSELECT: + return NewSelectStmt(pos, nil) + case OSEND: + return NewSendStmt(pos, nleft, nright) + case OSWITCH: + return NewSwitchStmt(pos, nleft, nil) + case OTYPESW: + return NewTypeSwitchGuard(pos, nleft, nright) default: n = new(node) } @@ -1067,15 +1105,7 @@ var okForNod = [OEND]bool{ OANDNOT: true, OAPPEND: true, OARRAYLIT: true, - OAS: true, - OAS2: true, - OAS2DOTTYPE: true, - OAS2FUNC: true, - OAS2MAPR: true, - OAS2RECV: true, - OASOP: true, OBITNOT: true, - OBLOCK: true, OBYTES2STR: true, OBYTES2STRTMP: true, OCALL: true, @@ -1083,7 +1113,6 @@ var okForNod = [OEND]bool{ OCALLINTER: true, OCALLMETH: true, OCAP: true, - OCASE: true, OCFUNC: true, OCHECKNIL: true, OCLOSE: true, @@ -1093,10 +1122,6 @@ var okForNod = [OEND]bool{ OCONVIFACE: true, OCONVNOP: true, OCOPY: true, - ODCL: true, - ODCLCONST: true, - ODCLTYPE: true, - ODEFER: true, ODELETE: true, ODIV: true, ODOT: true, @@ -1107,22 +1132,16 @@ var okForNod = [OEND]bool{ ODOTTYPE2: true, OEFACE: true, OEQ: true, - OFOR: true, - OFORUNTIL: true, OGE: true, OGETG: true, - OGO: true, OGT: true, OIDATA: true, - OIF: true, OIMAG: true, OINDEX: true, OINDEXMAP: true, OINLCALL: true, - OINLMARK: true, OITAB: true, OKEY: true, - OLABEL: true, OLE: true, OLEN: true, OLSH: true, @@ -1151,20 +1170,13 @@ var okForNod = [OEND]bool{ OPRINT: true, OPRINTN: true, OPTRLIT: true, - ORANGE: true, OREAL: true, ORECOVER: true, ORECV: true, ORESULT: true, - ORETJMP: true, - ORETURN: true, ORSH: true, ORUNES2STR: true, ORUNESTR: true, - OSELECT: true, - OSELRECV: true, - OSELRECV2: true, - OSEND: true, OSIZEOF: true, OSLICE: true, OSLICE3: true, @@ -1180,8 +1192,6 @@ var okForNod = [OEND]bool{ OSTRUCTKEY: true, OSTRUCTLIT: true, OSUB: true, - OSWITCH: true, - OTYPESW: true, OVARDEF: true, OVARKILL: true, OVARLIVE: true, diff --git a/src/cmd/compile/internal/ir/stmt.go b/src/cmd/compile/internal/ir/stmt.go index 5b89ff27a47..25168355136 100644 --- a/src/cmd/compile/internal/ir/stmt.go +++ b/src/cmd/compile/internal/ir/stmt.go @@ -10,6 +10,31 @@ import ( "fmt" ) +// A Decl is a declaration of a const, type, or var. (A declared func is a Func.) +// (This is not technically a statement but it's not worth its own file.) +type Decl struct { + miniNode + X Node // the thing being declared +} + +func NewDecl(pos src.XPos, op Op, x Node) *Decl { + n := &Decl{X: x} + n.pos = pos + switch op { + default: + panic("invalid Decl op " + op.String()) + case ODCL, ODCLCONST, ODCLTYPE: + n.op = op + } + return n +} + +func (n *Decl) String() string { return fmt.Sprint(n) } +func (n *Decl) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *Decl) RawCopy() Node { c := *n; return &c } +func (n *Decl) Left() Node { return n.X } +func (n *Decl) SetLeft(x Node) { n.X = x } + // A miniStmt is a miniNode with extra fields common to statements. type miniStmt struct { miniNode @@ -22,7 +47,148 @@ func (n *miniStmt) PtrInit() *Nodes { return &n.init } func (n *miniStmt) HasCall() bool { return n.bits&miniHasCall != 0 } func (n *miniStmt) SetHasCall(b bool) { n.bits.set(miniHasCall, b) } +// An AssignListStmt is an assignment statement with +// more than one item on at least one side: Lhs = Rhs. +// If Def is true, the assignment is a :=. +type AssignListStmt struct { + miniStmt + Lhs Nodes + Def bool + Rhs Nodes + offset int64 // for initorder +} + +func NewAssignListStmt(pos src.XPos, lhs, rhs []Node) *AssignListStmt { + n := &AssignListStmt{} + n.pos = pos + n.op = OAS2 + n.Lhs.Set(lhs) + n.Rhs.Set(rhs) + n.offset = types.BADWIDTH + return n +} + +func (n *AssignListStmt) String() string { return fmt.Sprint(n) } +func (n *AssignListStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *AssignListStmt) RawCopy() Node { c := *n; return &c } + +func (n *AssignListStmt) List() Nodes { return n.Lhs } +func (n *AssignListStmt) PtrList() *Nodes { return &n.Lhs } +func (n *AssignListStmt) SetList(x Nodes) { n.Lhs = x } +func (n *AssignListStmt) Rlist() Nodes { return n.Rhs } +func (n *AssignListStmt) PtrRlist() *Nodes { return &n.Rhs } +func (n *AssignListStmt) SetRlist(x Nodes) { n.Rhs = x } +func (n *AssignListStmt) Colas() bool { return n.Def } +func (n *AssignListStmt) SetColas(x bool) { n.Def = x } +func (n *AssignListStmt) Offset() int64 { return n.offset } +func (n *AssignListStmt) SetOffset(x int64) { n.offset = x } + +func (n *AssignListStmt) SetOp(op Op) { + switch op { + default: + panic(n.no("SetOp " + op.String())) + case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV, OSELRECV2: + n.op = op + } +} + +// An AssignStmt is a simple assignment statement: X = Y. +// If Def is true, the assignment is a :=. +type AssignStmt struct { + miniStmt + X Node + Def bool + Y Node + offset int64 // for initorder +} + +func NewAssignStmt(pos src.XPos, x, y Node) *AssignStmt { + n := &AssignStmt{X: x, Y: y} + n.pos = pos + n.op = OAS + n.offset = types.BADWIDTH + return n +} + +func (n *AssignStmt) String() string { return fmt.Sprint(n) } +func (n *AssignStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *AssignStmt) RawCopy() Node { c := *n; return &c } + +func (n *AssignStmt) Left() Node { return n.X } +func (n *AssignStmt) SetLeft(x Node) { n.X = x } +func (n *AssignStmt) Right() Node { return n.Y } +func (n *AssignStmt) SetRight(y Node) { n.Y = y } +func (n *AssignStmt) Colas() bool { return n.Def } +func (n *AssignStmt) SetColas(x bool) { n.Def = x } +func (n *AssignStmt) Offset() int64 { return n.offset } +func (n *AssignStmt) SetOffset(x int64) { n.offset = x } + +func (n *AssignStmt) SetOp(op Op) { + switch op { + default: + panic(n.no("SetOp " + op.String())) + case OAS, OSELRECV: + n.op = op + } +} + +// An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y. +type AssignOpStmt struct { + miniStmt + typ *types.Type + X Node + AsOp Op // OADD etc + Y Node + IncDec bool // actually ++ or -- +} + +func NewAssignOpStmt(pos src.XPos, op Op, x, y Node) *AssignOpStmt { + n := &AssignOpStmt{AsOp: op, X: x, Y: y} + n.pos = pos + n.op = OASOP + return n +} + +func (n *AssignOpStmt) String() string { return fmt.Sprint(n) } +func (n *AssignOpStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *AssignOpStmt) RawCopy() Node { c := *n; return &c } + +func (n *AssignOpStmt) Left() Node { return n.X } +func (n *AssignOpStmt) SetLeft(x Node) { n.X = x } +func (n *AssignOpStmt) Right() Node { return n.Y } +func (n *AssignOpStmt) SetRight(y Node) { n.Y = y } +func (n *AssignOpStmt) SubOp() Op { return n.AsOp } +func (n *AssignOpStmt) SetSubOp(x Op) { n.AsOp = x } +func (n *AssignOpStmt) Implicit() bool { return n.IncDec } +func (n *AssignOpStmt) SetImplicit(b bool) { n.IncDec = b } +func (n *AssignOpStmt) Type() *types.Type { return n.typ } +func (n *AssignOpStmt) SetType(x *types.Type) { n.typ = x } + +// A BlockStmt is a block: { List }. +type BlockStmt struct { + miniStmt + list Nodes +} + +func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt { + n := &BlockStmt{} + n.pos = pos + n.op = OBLOCK + n.list.Set(list) + return n +} + +func (n *BlockStmt) String() string { return fmt.Sprint(n) } +func (n *BlockStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *BlockStmt) RawCopy() Node { c := *n; return &c } +func (n *BlockStmt) List() Nodes { return n.list } +func (n *BlockStmt) PtrList() *Nodes { return &n.list } +func (n *BlockStmt) SetList(x Nodes) { n.list = x } + // A BranchStmt is a break, continue, fallthrough, or goto statement. +// +// For back-end code generation, Op may also be RETJMP (return+jump), +// in which case the label names another function entirely. type BranchStmt struct { miniStmt Label *types.Sym // label if present @@ -30,7 +196,7 @@ type BranchStmt struct { func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt { switch op { - case OBREAK, OCONTINUE, OFALL, OGOTO: + case OBREAK, OCONTINUE, OFALL, OGOTO, ORETJMP: // ok default: panic("NewBranch " + op.String()) @@ -47,6 +213,59 @@ func (n *BranchStmt) RawCopy() Node { c := *n; return &c } func (n *BranchStmt) Sym() *types.Sym { return n.Label } func (n *BranchStmt) SetSym(sym *types.Sym) { n.Label = sym } +// A CaseStmt is a case statement in a switch or select: case List: Body. +type CaseStmt struct { + miniStmt + Vars Nodes // declared variable for this case in type switch + list Nodes // list of expressions for switch, early select + Comm Node // communication case (Exprs[0]) after select is type-checked + body Nodes +} + +func NewCaseStmt(pos src.XPos, list, body []Node) *CaseStmt { + n := &CaseStmt{} + n.pos = pos + n.op = OCASE + n.list.Set(list) + n.body.Set(body) + return n +} + +func (n *CaseStmt) String() string { return fmt.Sprint(n) } +func (n *CaseStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *CaseStmt) RawCopy() Node { c := *n; return &c } +func (n *CaseStmt) List() Nodes { return n.list } +func (n *CaseStmt) PtrList() *Nodes { return &n.list } +func (n *CaseStmt) SetList(x Nodes) { n.list = x } +func (n *CaseStmt) Body() Nodes { return n.body } +func (n *CaseStmt) PtrBody() *Nodes { return &n.body } +func (n *CaseStmt) SetBody(x Nodes) { n.body = x } +func (n *CaseStmt) Rlist() Nodes { return n.Vars } +func (n *CaseStmt) PtrRlist() *Nodes { return &n.Vars } +func (n *CaseStmt) SetRlist(x Nodes) { n.Vars = x } +func (n *CaseStmt) Left() Node { return n.Comm } +func (n *CaseStmt) SetLeft(x Node) { n.Comm = x } + +// A DeferStmt is a defer statement: defer Call. +type DeferStmt struct { + miniStmt + Call Node +} + +func NewDeferStmt(pos src.XPos, call Node) *DeferStmt { + n := &DeferStmt{Call: call} + n.pos = pos + n.op = ODEFER + return n +} + +func (n *DeferStmt) String() string { return fmt.Sprint(n) } +func (n *DeferStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *DeferStmt) RawCopy() Node { c := *n; return &c } + +func (n *DeferStmt) Left() Node { return n.Call } +func (n *DeferStmt) SetLeft(x Node) { n.Call = x } + // An EmptyStmt is an empty statement type EmptyStmt struct { miniStmt @@ -63,6 +282,123 @@ func (n *EmptyStmt) String() string { return fmt.Sprint(n) } func (n *EmptyStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } func (n *EmptyStmt) RawCopy() Node { c := *n; return &c } +// A ForStmt is a non-range for loop: for Init; Cond; Post { Body } +// Op can be OFOR or OFORUNTIL (!Cond). +type ForStmt struct { + miniStmt + Label *types.Sym + Cond Node + Post Node + Late Nodes + body Nodes + hasBreak bool +} + +func NewForStmt(pos src.XPos, init []Node, cond, post Node, body []Node) *ForStmt { + n := &ForStmt{Cond: cond, Post: post} + n.pos = pos + n.op = OFOR + n.init.Set(init) + n.body.Set(body) + return n +} + +func (n *ForStmt) String() string { return fmt.Sprint(n) } +func (n *ForStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *ForStmt) RawCopy() Node { c := *n; return &c } +func (n *ForStmt) Sym() *types.Sym { return n.Label } +func (n *ForStmt) SetSym(x *types.Sym) { n.Label = x } +func (n *ForStmt) Left() Node { return n.Cond } +func (n *ForStmt) SetLeft(x Node) { n.Cond = x } +func (n *ForStmt) Right() Node { return n.Post } +func (n *ForStmt) SetRight(x Node) { n.Post = x } +func (n *ForStmt) Body() Nodes { return n.body } +func (n *ForStmt) PtrBody() *Nodes { return &n.body } +func (n *ForStmt) SetBody(x Nodes) { n.body = x } +func (n *ForStmt) List() Nodes { return n.Late } +func (n *ForStmt) PtrList() *Nodes { return &n.Late } +func (n *ForStmt) SetList(x Nodes) { n.Late = x } +func (n *ForStmt) HasBreak() bool { return n.hasBreak } +func (n *ForStmt) SetHasBreak(b bool) { n.hasBreak = b } + +func (n *ForStmt) SetOp(op Op) { + if op != OFOR && op != OFORUNTIL { + panic(n.no("SetOp " + op.String())) + } + n.op = op +} + +// A GoStmt is a go statement: go Call. +type GoStmt struct { + miniStmt + Call Node +} + +func NewGoStmt(pos src.XPos, call Node) *GoStmt { + n := &GoStmt{Call: call} + n.pos = pos + n.op = OGO + return n +} + +func (n *GoStmt) String() string { return fmt.Sprint(n) } +func (n *GoStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *GoStmt) RawCopy() Node { c := *n; return &c } + +func (n *GoStmt) Left() Node { return n.Call } +func (n *GoStmt) SetLeft(x Node) { n.Call = x } + +// A IfStmt is a return statement: if Init; Cond { Then } else { Else }. +type IfStmt struct { + miniStmt + Cond Node + body Nodes + Else Nodes + likely bool // code layout hint +} + +func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt { + n := &IfStmt{Cond: cond} + n.pos = pos + n.op = OIF + n.body.Set(body) + n.Else.Set(els) + return n +} + +func (n *IfStmt) String() string { return fmt.Sprint(n) } +func (n *IfStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *IfStmt) RawCopy() Node { c := *n; return &c } +func (n *IfStmt) Left() Node { return n.Cond } +func (n *IfStmt) SetLeft(x Node) { n.Cond = x } +func (n *IfStmt) Body() Nodes { return n.body } +func (n *IfStmt) PtrBody() *Nodes { return &n.body } +func (n *IfStmt) SetBody(x Nodes) { n.body = x } +func (n *IfStmt) Rlist() Nodes { return n.Else } +func (n *IfStmt) PtrRlist() *Nodes { return &n.Else } +func (n *IfStmt) SetRlist(x Nodes) { n.Else = x } +func (n *IfStmt) Likely() bool { return n.likely } +func (n *IfStmt) SetLikely(x bool) { n.likely = x } + +// An InlineMarkStmt is a marker placed just before an inlined body. +type InlineMarkStmt struct { + miniStmt + Index int64 +} + +func NewInlineMarkStmt(pos src.XPos, index int64) *InlineMarkStmt { + n := &InlineMarkStmt{Index: index} + n.pos = pos + n.op = OINLMARK + return n +} + +func (n *InlineMarkStmt) String() string { return fmt.Sprint(n) } +func (n *InlineMarkStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *InlineMarkStmt) RawCopy() Node { c := *n; return &c } +func (n *InlineMarkStmt) Offset() int64 { return n.Index } +func (n *InlineMarkStmt) SetOffset(x int64) { n.Index = x } + // A LabelStmt is a label statement (just the label, not including the statement it labels). type LabelStmt struct { miniStmt @@ -81,3 +417,200 @@ func (n *LabelStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } func (n *LabelStmt) RawCopy() Node { c := *n; return &c } func (n *LabelStmt) Sym() *types.Sym { return n.Label } func (n *LabelStmt) SetSym(x *types.Sym) { n.Label = x } + +// A RangeStmt is a range loop: for Vars = range X { Stmts } +// Op can be OFOR or OFORUNTIL (!Cond). +type RangeStmt struct { + miniStmt + Label *types.Sym + Vars Nodes // TODO(rsc): Replace with Key, Value Node + Def bool + X Node + body Nodes + hasBreak bool + typ *types.Type // TODO(rsc): Remove - use X.Type() instead +} + +func NewRangeStmt(pos src.XPos, vars []Node, x Node, body []Node) *RangeStmt { + n := &RangeStmt{X: x} + n.pos = pos + n.op = ORANGE + n.Vars.Set(vars) + n.body.Set(body) + return n +} + +func (n *RangeStmt) String() string { return fmt.Sprint(n) } +func (n *RangeStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *RangeStmt) RawCopy() Node { c := *n; return &c } +func (n *RangeStmt) Sym() *types.Sym { return n.Label } +func (n *RangeStmt) SetSym(x *types.Sym) { n.Label = x } +func (n *RangeStmt) Right() Node { return n.X } +func (n *RangeStmt) SetRight(x Node) { n.X = x } +func (n *RangeStmt) Body() Nodes { return n.body } +func (n *RangeStmt) PtrBody() *Nodes { return &n.body } +func (n *RangeStmt) SetBody(x Nodes) { n.body = x } +func (n *RangeStmt) List() Nodes { return n.Vars } +func (n *RangeStmt) PtrList() *Nodes { return &n.Vars } +func (n *RangeStmt) SetList(x Nodes) { n.Vars = x } +func (n *RangeStmt) HasBreak() bool { return n.hasBreak } +func (n *RangeStmt) SetHasBreak(b bool) { n.hasBreak = b } +func (n *RangeStmt) Colas() bool { return n.Def } +func (n *RangeStmt) SetColas(b bool) { n.Def = b } +func (n *RangeStmt) Type() *types.Type { return n.typ } +func (n *RangeStmt) SetType(x *types.Type) { n.typ = x } + +// A ReturnStmt is a return statement. +type ReturnStmt struct { + miniStmt + orig Node // for typecheckargs rewrite + Results Nodes // return list +} + +func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt { + n := &ReturnStmt{} + n.pos = pos + n.op = ORETURN + n.orig = n + n.Results.Set(results) + return n +} + +func (n *ReturnStmt) String() string { return fmt.Sprint(n) } +func (n *ReturnStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *ReturnStmt) RawCopy() Node { c := *n; return &c } +func (n *ReturnStmt) Orig() Node { return n.orig } +func (n *ReturnStmt) SetOrig(x Node) { n.orig = x } +func (n *ReturnStmt) List() Nodes { return n.Results } +func (n *ReturnStmt) PtrList() *Nodes { return &n.Results } +func (n *ReturnStmt) SetList(x Nodes) { n.Results = x } +func (n *ReturnStmt) IsDDD() bool { return false } // typecheckargs asks + +// A SelectStmt is a block: { Cases }. +type SelectStmt struct { + miniStmt + Label *types.Sym + Cases Nodes + hasBreak bool + + // TODO(rsc): Instead of recording here, replace with a block? + Compiled Nodes // compiled form, after walkswitch +} + +func NewSelectStmt(pos src.XPos, cases []Node) *SelectStmt { + n := &SelectStmt{} + n.pos = pos + n.op = OSELECT + n.Cases.Set(cases) + return n +} + +func (n *SelectStmt) String() string { return fmt.Sprint(n) } +func (n *SelectStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *SelectStmt) RawCopy() Node { c := *n; return &c } +func (n *SelectStmt) List() Nodes { return n.Cases } +func (n *SelectStmt) PtrList() *Nodes { return &n.Cases } +func (n *SelectStmt) SetList(x Nodes) { n.Cases = x } +func (n *SelectStmt) Sym() *types.Sym { return n.Label } +func (n *SelectStmt) SetSym(x *types.Sym) { n.Label = x } +func (n *SelectStmt) HasBreak() bool { return n.hasBreak } +func (n *SelectStmt) SetHasBreak(x bool) { n.hasBreak = x } +func (n *SelectStmt) Body() Nodes { return n.Compiled } +func (n *SelectStmt) PtrBody() *Nodes { return &n.Compiled } +func (n *SelectStmt) SetBody(x Nodes) { n.Compiled = x } + +// A SendStmt is a send statement: X <- Y. +type SendStmt struct { + miniStmt + Chan Node + Value Node +} + +func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt { + n := &SendStmt{Chan: ch, Value: value} + n.pos = pos + n.op = OSEND + return n +} + +func (n *SendStmt) String() string { return fmt.Sprint(n) } +func (n *SendStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *SendStmt) RawCopy() Node { c := *n; return &c } + +func (n *SendStmt) Left() Node { return n.Chan } +func (n *SendStmt) SetLeft(x Node) { n.Chan = x } +func (n *SendStmt) Right() Node { return n.Value } +func (n *SendStmt) SetRight(y Node) { n.Value = y } + +// A SwitchStmt is a switch statement: switch Init; Expr { Cases }. +type SwitchStmt struct { + miniStmt + Tag Node + Cases Nodes // list of *CaseStmt + Label *types.Sym + hasBreak bool + + // TODO(rsc): Instead of recording here, replace with a block? + Compiled Nodes // compiled form, after walkswitch +} + +func NewSwitchStmt(pos src.XPos, tag Node, cases []Node) *SwitchStmt { + n := &SwitchStmt{Tag: tag} + n.pos = pos + n.op = OSWITCH + n.Cases.Set(cases) + return n +} + +func (n *SwitchStmt) String() string { return fmt.Sprint(n) } +func (n *SwitchStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *SwitchStmt) RawCopy() Node { c := *n; return &c } +func (n *SwitchStmt) Left() Node { return n.Tag } +func (n *SwitchStmt) SetLeft(x Node) { n.Tag = x } +func (n *SwitchStmt) List() Nodes { return n.Cases } +func (n *SwitchStmt) PtrList() *Nodes { return &n.Cases } +func (n *SwitchStmt) SetList(x Nodes) { n.Cases = x } +func (n *SwitchStmt) Body() Nodes { return n.Compiled } +func (n *SwitchStmt) PtrBody() *Nodes { return &n.Compiled } +func (n *SwitchStmt) SetBody(x Nodes) { n.Compiled = x } +func (n *SwitchStmt) Sym() *types.Sym { return n.Label } +func (n *SwitchStmt) SetSym(x *types.Sym) { n.Label = x } +func (n *SwitchStmt) HasBreak() bool { return n.hasBreak } +func (n *SwitchStmt) SetHasBreak(x bool) { n.hasBreak = x } + +// A TypeSwitchGuard is the [Name :=] X.(type) in a type switch. +type TypeSwitchGuard struct { + miniNode + name *Name + X Node +} + +func NewTypeSwitchGuard(pos src.XPos, name, x Node) *TypeSwitchGuard { + n := &TypeSwitchGuard{X: x} + if name != nil { + n.name = name.(*Name) + } + n.pos = pos + n.op = OTYPESW + return n +} + +func (n *TypeSwitchGuard) String() string { return fmt.Sprint(n) } +func (n *TypeSwitchGuard) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } +func (n *TypeSwitchGuard) RawCopy() Node { c := *n; return &c } + +func (n *TypeSwitchGuard) Left() Node { + if n.name == nil { + return nil + } + return n.name +} +func (n *TypeSwitchGuard) SetLeft(x Node) { + if x == nil { + n.name = nil + return + } + n.name = x.(*Name) +} +func (n *TypeSwitchGuard) Right() Node { return n.X } +func (n *TypeSwitchGuard) SetRight(x Node) { n.X = x }