Example #1
0
// stmt generates code for statements.
func (c *compiler) stmt(s ast.Stmt) {
	pos := s.Span().Start
	switch s := s.(type) {
	case *ast.EmptyStmt, *ast.BadStmt:
		// skip
	case *ast.BlockStmt:
		for _, x := range s.Stmt {
			c.stmt(x)
		}
	case *ast.IfStmt:
		c.ifStmt(s)
	case *ast.ForStmt:
		c.forStmt(s)
	case *ast.DoStmt:
		c.doStmt(s)
	case *ast.WhileStmt:
		c.whileStmt(s)
	case *ast.ReturnStmt:
		c.returnStmt(s)
	case *ast.SwitchStmt:
		c.switchStmt(s)
	case *ast.GotoStmt:
		c.cg.Jump(c.labels[s.Label.Name])
	case *ast.LabeledStmt:
		c.cg.Lab(c.labels[s.Label.Name])
		c.stmt(s.Stmt)
	case *ast.BranchStmt:
		switch s.Type {
		case scan.Break:
			c.cg.Jump(c.breakStack[len(c.breakStack)-1])
		case scan.Continue:
			c.cg.Jump(c.continueStack[len(c.continueStack)-1])
		default:
			c.invalidAST(pos, "bad statement: %T", s)
		}
	case *ast.ExprStmt:
		c.expr(s.X)
		c.cg.Commit()
	default:
		c.invalidAST(pos, "bad statement: %T", s)
	}
	c.cg.Clear(true)
}
Example #2
0
// stmt type checks a statement.
func (c *checker) stmt(ctx stmtContext, s ast.Stmt) {
	var x operand

	pos := s.Span().Start
	inner := ctx

	c.recordScope(s, c.scope)
	switch s := s.(type) {
	case *ast.BadStmt, *ast.EmptyStmt:
		// ignore

	case *ast.BranchStmt:
		switch s.Type {
		case scan.Break:
			if ctx&breakOk == 0 {
				c.errorf(pos, "break not in for/while or switch statement")
			}
		case scan.Continue:
			if ctx&continueOk == 0 {
				c.errorf(pos, "continue not in for/while statement")
			}
		default:
			c.invalidAST(pos, "branch statement: %s", s.Text)
		}

	case *ast.BlockStmt:
		c.openScope(s)
		defer c.closeScope()
		c.stmtList(inner, s.Stmt)

	case *ast.DoStmt:
		inner |= breakOk | continueOk
		c.stmt(inner, s.Body)
		c.expr(&x, s.Cond)

	case *ast.ExprStmt:
		c.expr(&x, s.X)

	case *ast.GotoStmt:
		obj, _ := c.scope.LookupParent(Lab, s.Label.Name, scan.NoPos)
		if obj == nil {
			c.errorf(pos, "goto cannot jump to non-existent label %v", s.Label.Name)
		}

	case *ast.LabeledStmt:
		c.stmt(inner, s.Stmt)

	case *ast.IfStmt:
		c.expr(&x, s.Cond)
		c.stmt(inner, s.Body)
		if s.Else != nil {
			c.stmt(inner, s.Else)
		}

	case *ast.ForStmt:
		inner |= breakOk | continueOk
		c.simpleStmt(s.Init)
		if s.Cond != nil {
			c.expr(&x, s.Cond)
		}
		c.simpleStmt(s.Post)
		c.stmt(inner, s.Body)

	case *ast.ReturnStmt:
		if s.X != nil {
			c.expr(&x, s.X)
		} else {
			x.mode = novalue
		}

	case *ast.SwitchStmt:
		inner |= breakOk
		c.expr(&x, s.Tag)

		sawCases := make(map[constant.Value]scanner.Position)
		defaultPos := scan.NoPos
		for _, n := range s.Body.Stmt {
			xpos := n.Span().Start
			switch n := n.(type) {
			case *ast.CaseClause:
				if n.Value != nil {
					c.expr(&x, n.Value)
					xpos := x.pos()
					if x.typ == Typ[Invalid] {
						continue
					}

					_, err := strconv.Atoi(x.val.String())
					if x.mode != constant_ || err != nil {
						c.errorf(xpos, "non-constant integer in case statement")
						continue
					}

					if cpos, found := sawCases[x.val]; found {
						c.errorf(xpos, "duplicate case value")
						c.errorf(cpos, "\tpreviously used here")
					} else {
						sawCases[x.val] = n.Case.Span().Start
					}
				} else if defaultPos != scan.NoPos {
					c.errorf(xpos, "multiple defaults in one switch")
					c.errorf(defaultPos, "\tthis is the first default label")
				} else {
					defaultPos = xpos
				}
				c.stmtList(inner, n.Body)

			default:
				c.errorf(xpos, "switch only supports case/default clauses, got %T", n)
			}
		}
		if len(s.Body.Stmt) == 0 {
			c.errorf(pos, "empty switch statement")
		}

	case *ast.WhileStmt:
		inner |= breakOk | continueOk
		c.expr(&x, s.Cond)
		c.stmt(inner, s.Body)

	case *ast.BinaryExpr:
		c.expr(&x, s)

	case *ast.UnaryExpr:
		c.expr(&x, s)

	default:
		c.errorf(pos, "invalid statement: %T", s)
	}
}