Пример #1
0
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()}
}
Пример #2
0
// 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
}
Пример #3
0
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")
}