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  }