func (p *parser) makeExpr(s ast.Stmt) ast.Expr { if s == nil { return nil } if es, isExpr := s.(*ast.ExprStmt); isExpr { return p.checkExpr(es.X) } p.error(s.Pos(), "expected condition, found simple statement") return &ast.BadExpr{s.Pos(), s.End()} }
// Sets multiLine to true if the statements spans multiple lines. func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { p.print(stmt.Pos()) switch s := stmt.(type) { case *ast.BadStmt: p.print("BadStmt") case *ast.DeclStmt: p.decl(s.Decl, multiLine) case *ast.EmptyStmt: // nothing to do case *ast.LabeledStmt: // a "correcting" unindent immediately following a line break // is applied before the line break if there is no comment // between (see writeWhitespace) p.print(unindent) p.expr(s.Label, multiLine) p.print(s.Colon, token.COLON, indent) if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty { if !nextIsRBrace { p.print(newline, e.Pos(), token.SEMICOLON) break } } else { p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignore, true) } p.stmt(s.Stmt, nextIsRBrace, multiLine) case *ast.ExprStmt: const depth = 1 p.expr0(s.X, depth, multiLine) case *ast.SendStmt: const depth = 1 p.expr0(s.Chan, depth, multiLine) p.print(blank, s.Arrow, token.ARROW, blank) p.expr0(s.Value, depth, multiLine) case *ast.IncDecStmt: const depth = 1 p.expr0(s.X, depth+1, multiLine) p.print(s.TokPos, s.Tok) case *ast.AssignStmt: var depth = 1 if len(s.Lhs) > 1 && len(s.Rhs) > 1 { depth++ } p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos) p.print(blank, s.TokPos, s.Tok) p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos) case *ast.GoStmt: p.print(token.GO, blank) p.expr(s.Call, multiLine) case *ast.DeferStmt: p.print(token.DEFER, blank) p.expr(s.Call, multiLine) case *ast.ReturnStmt: *multiLine = false p.print(token.RETURN) if s.Results != nil { p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos) } case *ast.BranchStmt: p.print(s.Tok) if s.Label != nil { p.print(blank) p.expr(s.Label, multiLine) } case *ast.BlockStmt: p.block(s, 1) *multiLine = true case *ast.IfStmt: p.print(token.IF) p.controlClause(false, s.Init, s.Cond, nil) p.block(s.Body, 1) *multiLine = true if s.Else != nil { p.print(blank, token.ELSE, blank) switch s.Else.(type) { case *ast.BlockStmt, *ast.IfStmt: p.stmt(s.Else, nextIsRBrace, ignoreMultiLine) default: p.print(token.LBRACE, indent, formfeed) p.stmt(s.Else, true, ignoreMultiLine) p.print(unindent, formfeed, token.RBRACE) } } case *ast.CaseClause: if s.Values != nil { p.print(token.CASE) p.exprList(s.Pos(), s.Values, 1, blankStart|commaSep, multiLine, s.Colon) } else { p.print(token.DEFAULT) } p.print(s.Colon, token.COLON) p.stmtList(s.Body, 1, nextIsRBrace) case *ast.SwitchStmt: p.print(token.SWITCH) p.controlClause(false, s.Init, s.Tag, nil) p.block(s.Body, 0) *multiLine = true case *ast.TypeCaseClause: if s.Types != nil { p.print(token.CASE) p.exprList(s.Pos(), s.Types, 1, blankStart|commaSep, multiLine, s.Colon) } else { p.print(token.DEFAULT) } p.print(s.Colon, token.COLON) p.stmtList(s.Body, 1, nextIsRBrace) case *ast.TypeSwitchStmt: p.print(token.SWITCH) if s.Init != nil { p.print(blank) p.stmt(s.Init, false, ignoreMultiLine) p.print(token.SEMICOLON) } p.print(blank) p.stmt(s.Assign, false, ignoreMultiLine) p.print(blank) p.block(s.Body, 0) *multiLine = true case *ast.CommClause: if s.Comm != nil { p.print(token.CASE, blank) p.stmt(s.Comm, false, ignoreMultiLine) } else { p.print(token.DEFAULT) } p.print(s.Colon, token.COLON) p.stmtList(s.Body, 1, nextIsRBrace) case *ast.SelectStmt: p.print(token.SELECT, blank) p.block(s.Body, 0) *multiLine = true case *ast.ForStmt: p.print(token.FOR) p.controlClause(true, s.Init, s.Cond, s.Post) p.block(s.Body, 1) *multiLine = true case *ast.RangeStmt: p.print(token.FOR, blank) p.expr(s.Key, multiLine) if s.Value != nil { p.print(token.COMMA, blank) p.expr(s.Value, multiLine) } p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank) p.expr(stripParens(s.X), multiLine) p.print(blank) p.block(s.Body, 1) *multiLine = true default: panic("unreachable") } return }
func (p *parser) parseForStmt() ast.Stmt { if p.trace { defer un(trace(p, "ForStmt")) } pos := p.expect(token.FOR) var s1, s2, s3 ast.Stmt if p.tok != token.LBRACE { prevLev := p.exprLev p.exprLev = -1 if p.tok != token.SEMICOLON { s2 = p.parseSimpleStmt(false) } if p.tok == token.SEMICOLON { p.next() s1 = s2 s2 = nil if p.tok != token.SEMICOLON { s2 = p.parseSimpleStmt(false) } p.expectSemi() if p.tok != token.LBRACE { s3 = p.parseSimpleStmt(false) } } p.exprLev = prevLev } body := p.parseBlockStmt() p.expectSemi() if as, isAssign := s2.(*ast.AssignStmt); isAssign { // possibly a for statement with a range clause; check assignment operator if as.Tok != token.ASSIGN && as.Tok != token.DEFINE { p.errorExpected(as.TokPos, "'=' or ':='") return &ast.BadStmt{pos, body.End()} } // check lhs var key, value ast.Expr switch len(as.Lhs) { case 2: key, value = as.Lhs[0], as.Lhs[1] case 1: key = as.Lhs[0] default: p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions") return &ast.BadStmt{pos, body.End()} } // check rhs if len(as.Rhs) != 1 { p.errorExpected(as.Rhs[0].Pos(), "1 expression") return &ast.BadStmt{pos, body.End()} } if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE { // rhs is range expression; check lhs return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body} } else { p.errorExpected(s2.Pos(), "range clause") return &ast.BadStmt{pos, body.End()} } } else { // regular for statement return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body} } panic("unreachable") }