github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/noder/stmt.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package noder 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 9 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 10 "github.com/bir3/gocompiler/src/cmd/compile/internal/syntax" 11 "github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck" 12 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 13 "github.com/bir3/gocompiler/src/cmd/internal/src" 14 ) 15 16 // stmts creates nodes for a slice of statements that form a scope. 17 func (g *irgen) stmts(stmts []syntax.Stmt) []ir.Node { 18 var nodes []ir.Node 19 types.Markdcl() 20 for _, stmt := range stmts { 21 switch s := g.stmt(stmt).(type) { 22 case nil: // EmptyStmt 23 case *ir.BlockStmt: 24 nodes = append(nodes, s.List...) 25 default: 26 nodes = append(nodes, s) 27 } 28 } 29 types.Popdcl() 30 return nodes 31 } 32 33 func (g *irgen) stmt(stmt syntax.Stmt) ir.Node { 34 base.Assert(g.exprStmtOK) 35 switch stmt := stmt.(type) { 36 case nil, *syntax.EmptyStmt: 37 return nil 38 case *syntax.LabeledStmt: 39 return g.labeledStmt(stmt) 40 case *syntax.BlockStmt: 41 return ir.NewBlockStmt(g.pos(stmt), g.blockStmt(stmt)) 42 case *syntax.ExprStmt: 43 return wrapname(g.pos(stmt.X), g.expr(stmt.X)) 44 case *syntax.SendStmt: 45 n := ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value)) 46 if !g.delayTransform() { 47 transformSend(n) 48 } 49 n.SetTypecheck(1) 50 return n 51 case *syntax.DeclStmt: 52 if g.topFuncIsGeneric && len(stmt.DeclList) > 0 { 53 if _, ok := stmt.DeclList[0].(*syntax.TypeDecl); ok { 54 // TODO: remove this restriction. See issue 47631. 55 base.ErrorfAt(g.pos(stmt), "type declarations inside generic functions are not currently supported") 56 } 57 } 58 n := ir.NewBlockStmt(g.pos(stmt), nil) 59 g.decls(&n.List, stmt.DeclList) 60 return n 61 62 case *syntax.AssignStmt: 63 if stmt.Op != 0 && stmt.Op != syntax.Def { 64 op := g.op(stmt.Op, binOps[:]) 65 var n *ir.AssignOpStmt 66 if stmt.Rhs == nil { 67 n = IncDec(g.pos(stmt), op, g.expr(stmt.Lhs)) 68 } else { 69 // Eval rhs before lhs, for compatibility with noder1 70 rhs := g.expr(stmt.Rhs) 71 lhs := g.expr(stmt.Lhs) 72 n = ir.NewAssignOpStmt(g.pos(stmt), op, lhs, rhs) 73 } 74 if !g.delayTransform() { 75 transformAsOp(n) 76 } 77 n.SetTypecheck(1) 78 return n 79 } 80 81 // Eval rhs before lhs, for compatibility with noder1 82 rhs := g.exprList(stmt.Rhs) 83 names, lhs := g.assignList(stmt.Lhs, stmt.Op == syntax.Def) 84 85 if len(lhs) == 1 && len(rhs) == 1 { 86 n := ir.NewAssignStmt(g.pos(stmt), lhs[0], rhs[0]) 87 n.Def = initDefn(n, names) 88 89 if !g.delayTransform() { 90 lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y} 91 transformAssign(n, lhs, rhs) 92 n.X, n.Y = lhs[0], rhs[0] 93 } 94 n.SetTypecheck(1) 95 return n 96 } 97 98 n := ir.NewAssignListStmt(g.pos(stmt), ir.OAS2, lhs, rhs) 99 n.Def = initDefn(n, names) 100 if !g.delayTransform() { 101 transformAssign(n, n.Lhs, n.Rhs) 102 } 103 n.SetTypecheck(1) 104 return n 105 106 case *syntax.BranchStmt: 107 return ir.NewBranchStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), branchOps[:]), g.name(stmt.Label)) 108 case *syntax.CallStmt: 109 return ir.NewGoDeferStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), callOps[:]), g.expr(stmt.Call)) 110 case *syntax.ReturnStmt: 111 n := ir.NewReturnStmt(g.pos(stmt), g.exprList(stmt.Results)) 112 if !g.delayTransform() { 113 transformReturn(n) 114 } 115 n.SetTypecheck(1) 116 return n 117 case *syntax.IfStmt: 118 return g.ifStmt(stmt) 119 case *syntax.ForStmt: 120 return g.forStmt(stmt) 121 case *syntax.SelectStmt: 122 n := g.selectStmt(stmt) 123 124 if !g.delayTransform() { 125 transformSelect(n.(*ir.SelectStmt)) 126 } 127 n.SetTypecheck(1) 128 return n 129 case *syntax.SwitchStmt: 130 return g.switchStmt(stmt) 131 132 default: 133 g.unhandled("statement", stmt) 134 panic("unreachable") 135 } 136 } 137 138 // TODO(mdempsky): Investigate replacing with switch statements or dense arrays. 139 140 var branchOps = [...]ir.Op{ 141 syntax.Break: ir.OBREAK, 142 syntax.Continue: ir.OCONTINUE, 143 syntax.Fallthrough: ir.OFALL, 144 syntax.Goto: ir.OGOTO, 145 } 146 147 var callOps = [...]ir.Op{ 148 syntax.Defer: ir.ODEFER, 149 syntax.Go: ir.OGO, 150 } 151 152 func (g *irgen) tokOp(tok int, ops []ir.Op) ir.Op { 153 // TODO(mdempsky): Validate. 154 return ops[tok] 155 } 156 157 func (g *irgen) op(op syntax.Operator, ops []ir.Op) ir.Op { 158 // TODO(mdempsky): Validate. 159 return ops[op] 160 } 161 162 func (g *irgen) assignList(expr syntax.Expr, def bool) ([]*ir.Name, []ir.Node) { 163 if !def { 164 return nil, g.exprList(expr) 165 } 166 167 var exprs []syntax.Expr 168 if list, ok := expr.(*syntax.ListExpr); ok { 169 exprs = list.ElemList 170 } else { 171 exprs = []syntax.Expr{expr} 172 } 173 174 var names []*ir.Name 175 res := make([]ir.Node, len(exprs)) 176 for i, expr := range exprs { 177 expr := expr.(*syntax.Name) 178 if expr.Value == "_" { 179 res[i] = ir.BlankNode 180 continue 181 } 182 183 if obj, ok := g.info.Uses[expr]; ok { 184 res[i] = g.obj(obj) 185 continue 186 } 187 188 name, _ := g.def(expr) 189 names = append(names, name) 190 res[i] = name 191 } 192 193 return names, res 194 } 195 196 // initDefn marks the given names as declared by defn and populates 197 // its Init field with ODCL nodes. It then reports whether any names 198 // were so declared, which can be used to initialize defn.Def. 199 func initDefn(defn ir.InitNode, names []*ir.Name) bool { 200 if len(names) == 0 { 201 return false 202 } 203 204 init := make([]ir.Node, len(names)) 205 for i, name := range names { 206 name.Defn = defn 207 init[i] = ir.NewDecl(name.Pos(), ir.ODCL, name) 208 } 209 defn.SetInit(init) 210 return true 211 } 212 213 func (g *irgen) blockStmt(stmt *syntax.BlockStmt) []ir.Node { 214 return g.stmts(stmt.List) 215 } 216 217 func (g *irgen) ifStmt(stmt *syntax.IfStmt) ir.Node { 218 init := g.stmt(stmt.Init) 219 n := ir.NewIfStmt(g.pos(stmt), g.expr(stmt.Cond), g.blockStmt(stmt.Then), nil) 220 if stmt.Else != nil { 221 e := g.stmt(stmt.Else) 222 if e.Op() == ir.OBLOCK { 223 e := e.(*ir.BlockStmt) 224 n.Else = e.List 225 } else { 226 n.Else = []ir.Node{e} 227 } 228 } 229 return g.init(init, n) 230 } 231 232 // unpackTwo returns the first two nodes in list. If list has fewer 233 // than 2 nodes, then the missing nodes are replaced with nils. 234 func unpackTwo(list []ir.Node) (fst, snd ir.Node) { 235 switch len(list) { 236 case 0: 237 return nil, nil 238 case 1: 239 return list[0], nil 240 default: 241 return list[0], list[1] 242 } 243 } 244 245 func (g *irgen) forStmt(stmt *syntax.ForStmt) ir.Node { 246 if r, ok := stmt.Init.(*syntax.RangeClause); ok { 247 names, lhs := g.assignList(r.Lhs, r.Def) 248 key, value := unpackTwo(lhs) 249 n := ir.NewRangeStmt(g.pos(r), key, value, g.expr(r.X), g.blockStmt(stmt.Body)) 250 n.Def = initDefn(n, names) 251 if key != nil { 252 transformCheckAssign(n, key) 253 } 254 if value != nil { 255 transformCheckAssign(n, value) 256 } 257 return n 258 } 259 260 return ir.NewForStmt(g.pos(stmt), g.stmt(stmt.Init), g.expr(stmt.Cond), g.stmt(stmt.Post), g.blockStmt(stmt.Body)) 261 } 262 263 func (g *irgen) selectStmt(stmt *syntax.SelectStmt) ir.Node { 264 body := make([]*ir.CommClause, len(stmt.Body)) 265 for i, clause := range stmt.Body { 266 body[i] = ir.NewCommStmt(g.pos(clause), g.stmt(clause.Comm), g.stmts(clause.Body)) 267 } 268 return ir.NewSelectStmt(g.pos(stmt), body) 269 } 270 271 func (g *irgen) switchStmt(stmt *syntax.SwitchStmt) ir.Node { 272 pos := g.pos(stmt) 273 init := g.stmt(stmt.Init) 274 275 var expr ir.Node 276 switch tag := stmt.Tag.(type) { 277 case *syntax.TypeSwitchGuard: 278 var ident *ir.Ident 279 if tag.Lhs != nil { 280 ident = ir.NewIdent(g.pos(tag.Lhs), g.name(tag.Lhs)) 281 } 282 expr = ir.NewTypeSwitchGuard(pos, ident, g.expr(tag.X)) 283 default: 284 expr = g.expr(tag) 285 } 286 287 body := make([]*ir.CaseClause, len(stmt.Body)) 288 for i, clause := range stmt.Body { 289 // Check for an implicit clause variable before 290 // visiting body, because it may contain function 291 // literals that reference it, and then it'll be 292 // associated to the wrong function. 293 // 294 // Also, override its position to the clause's colon, so that 295 // dwarfgen can find the right scope for it later. 296 // TODO(mdempsky): We should probably just store the scope 297 // directly in the ir.Name. 298 var cv *ir.Name 299 if obj, ok := g.info.Implicits[clause]; ok { 300 cv = g.obj(obj) 301 cv.SetPos(g.makeXPos(clause.Colon)) 302 assert(expr.Op() == ir.OTYPESW) 303 cv.Defn = expr 304 } 305 body[i] = ir.NewCaseStmt(g.pos(clause), g.exprList(clause.Cases), g.stmts(clause.Body)) 306 body[i].Var = cv 307 } 308 309 return g.init(init, ir.NewSwitchStmt(pos, expr, body)) 310 } 311 312 func (g *irgen) labeledStmt(label *syntax.LabeledStmt) ir.Node { 313 sym := g.name(label.Label) 314 lhs := ir.NewLabelStmt(g.pos(label), sym) 315 ls := g.stmt(label.Stmt) 316 317 // Attach label directly to control statement too. 318 switch ls := ls.(type) { 319 case *ir.ForStmt: 320 ls.Label = sym 321 case *ir.RangeStmt: 322 ls.Label = sym 323 case *ir.SelectStmt: 324 ls.Label = sym 325 case *ir.SwitchStmt: 326 ls.Label = sym 327 } 328 329 l := []ir.Node{lhs} 330 if ls != nil { 331 if ls.Op() == ir.OBLOCK { 332 ls := ls.(*ir.BlockStmt) 333 l = append(l, ls.List...) 334 } else { 335 l = append(l, ls) 336 } 337 } 338 return ir.NewBlockStmt(src.NoXPos, l) 339 } 340 341 func (g *irgen) init(init ir.Node, stmt ir.InitNode) ir.InitNode { 342 if init != nil { 343 stmt.SetInit([]ir.Node{init}) 344 } 345 return stmt 346 } 347 348 func (g *irgen) name(name *syntax.Name) *types.Sym { 349 if name == nil { 350 return nil 351 } 352 return typecheck.Lookup(name.Value) 353 }