// checkExprOrType checks that x is an expression or a type // (and not a raw type such as [...]T). // func (p *parser) checkExprOrType(x ast.Expr) ast.Expr { switch t := unparen(x).(type) { case *ast.ParenExpr: panic("unreachable") case *ast.UnaryExpr: if t.Op == token.RANGE { // the range operator is only allowed at the top of a for statement p.errorExpected(x.Pos(), "expression") x = &ast.BadExpr{x.Pos(), x.End()} } case *ast.ArrayType: if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis { p.error(len.Pos(), "expected array length, found '...'") x = &ast.BadExpr{x.Pos(), x.End()} } } // all other nodes are expressions or types return x }
// Sets multiLine to true if the expression spans multiple lines. func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multiLine *bool) { p.print(expr.Pos()) switch x := expr.(type) { case *ast.BadExpr: p.print("BadExpr") case *ast.Ident: p.print(x) case *ast.BinaryExpr: if depth < 1 { p.internalError("depth < 1:", depth) depth = 1 } p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine) case *ast.KeyValueExpr: p.expr(x.Key, multiLine) p.print(x.Colon, token.COLON, blank) p.expr(x.Value, multiLine) case *ast.StarExpr: const prec = token.UnaryPrec if prec < prec1 { // parenthesis needed p.print(token.LPAREN) p.print(token.MUL) p.expr(x.X, multiLine) p.print(token.RPAREN) } else { // no parenthesis needed p.print(token.MUL) p.expr(x.X, multiLine) } case *ast.UnaryExpr: const prec = token.UnaryPrec if prec < prec1 { // parenthesis needed p.print(token.LPAREN) p.expr(x, multiLine) p.print(token.RPAREN) } else { // no parenthesis needed p.print(x.Op) if x.Op == token.RANGE { // TODO(gri) Remove this code if it cannot be reached. p.print(blank) } p.expr1(x.X, prec, depth, 0, multiLine) } case *ast.BasicLit: p.print(x) case *ast.FuncLit: p.expr(x.Type, multiLine) p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine) case *ast.ParenExpr: if _, hasParens := x.X.(*ast.ParenExpr); hasParens { // don't print parentheses around an already parenthesized expression // TODO(gri) consider making this more general and incorporate precedence levels p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth } else { p.print(token.LPAREN) p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth p.print(x.Rparen, token.RPAREN) } case *ast.SelectorExpr: parts := selectorExprList(expr) p.exprList(token.NoPos, parts, depth, periodSep, multiLine, token.NoPos) case *ast.TypeAssertExpr: p.expr1(x.X, token.HighestPrec, depth, 0, multiLine) p.print(token.PERIOD, token.LPAREN) if x.Type != nil { p.expr(x.Type, multiLine) } else { p.print(token.TYPE) } p.print(token.RPAREN) case *ast.IndexExpr: // TODO(gri): should treat[] like parentheses and undo one level of depth p.expr1(x.X, token.HighestPrec, 1, 0, multiLine) p.print(x.Lbrack, token.LBRACK) p.expr0(x.Index, depth+1, multiLine) p.print(x.Rbrack, token.RBRACK) case *ast.SliceExpr: // TODO(gri): should treat[] like parentheses and undo one level of depth p.expr1(x.X, token.HighestPrec, 1, 0, multiLine) p.print(x.Lbrack, token.LBRACK) if x.Low != nil { p.expr0(x.Low, depth+1, multiLine) } // blanks around ":" if both sides exist and either side is a binary expression if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) { p.print(blank, token.COLON, blank) } else { p.print(token.COLON) } if x.High != nil { p.expr0(x.High, depth+1, multiLine) } p.print(x.Rbrack, token.RBRACK) case *ast.CallExpr: if len(x.Args) > 1 { depth++ } p.expr1(x.Fun, token.HighestPrec, depth, 0, multiLine) p.print(x.Lparen, token.LPAREN) p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen) if x.Ellipsis.IsValid() { p.print(x.Ellipsis, token.ELLIPSIS) } p.print(x.Rparen, token.RPAREN) case *ast.CompositeLit: // composite literal elements that are composite literals themselves may have the type omitted if x.Type != nil { p.expr1(x.Type, token.HighestPrec, depth, compositeLit, multiLine) } p.print(x.Lbrace, token.LBRACE) p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace) // do not insert extra line breaks because of comments before // the closing '}' as it might break the code if there is no // trailing ',' p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak) case *ast.Ellipsis: p.print(token.ELLIPSIS) if x.Elt != nil { p.expr(x.Elt, multiLine) } case *ast.ArrayType: p.print(token.LBRACK) if x.Len != nil { p.expr(x.Len, multiLine) } p.print(token.RBRACK) p.expr(x.Elt, multiLine) case *ast.StructType: p.print(token.STRUCT) p.fieldList(x.Fields, x.Incomplete, ctxt|structType) case *ast.FuncType: p.print(token.FUNC) p.signature(x.Params, x.Results, multiLine) case *ast.InterfaceType: p.print(token.INTERFACE) p.fieldList(x.Methods, x.Incomplete, ctxt) case *ast.MapType: p.print(token.MAP, token.LBRACK) p.expr(x.Key, multiLine) p.print(token.RBRACK) p.expr(x.Value, multiLine) case *ast.ChanType: switch x.Dir { case ast.SEND | ast.RECV: p.print(token.CHAN) case ast.RECV: p.print(token.ARROW, token.CHAN) case ast.SEND: p.print(token.CHAN, token.ARROW) } p.print(blank) p.expr(x.Value, multiLine) default: panic("unreachable") } return }
// checkExpr checks that x is an expression (and not a type). func (p *parser) checkExpr(x ast.Expr) ast.Expr { switch t := unparen(x).(type) { case *ast.BadExpr: case *ast.Ident: case *ast.BasicLit: case *ast.FuncLit: case *ast.CompositeLit: case *ast.ParenExpr: panic("unreachable") case *ast.SelectorExpr: case *ast.IndexExpr: case *ast.SliceExpr: case *ast.TypeAssertExpr: if t.Type == nil { // the form X.(type) is only allowed in type switch expressions p.errorExpected(x.Pos(), "expression") x = &ast.BadExpr{x.Pos(), x.End()} } case *ast.CallExpr: case *ast.StarExpr: case *ast.UnaryExpr: if t.Op == token.RANGE { // the range operator is only allowed at the top of a for statement p.errorExpected(x.Pos(), "expression") x = &ast.BadExpr{x.Pos(), x.End()} } case *ast.BinaryExpr: default: // all other nodes are not proper expressions p.errorExpected(x.Pos(), "expression") x = &ast.BadExpr{x.Pos(), x.End()} } return x }
func (p *parser) parseCommClause() *ast.CommClause { if p.trace { defer un(trace(p, "CommClause")) } // CommCase pos := p.pos var comm ast.Stmt if p.tok == token.CASE { p.next() lhs := p.parseExprList() if p.tok == token.ARROW { // SendStmt if len(lhs) > 1 { p.errorExpected(lhs[0].Pos(), "1 expression") // continue with first expression } arrow := p.pos p.next() rhs := p.parseExpr() comm = &ast.SendStmt{lhs[0], arrow, rhs} } else { // RecvStmt pos := p.pos tok := p.tok var rhs ast.Expr if p.tok == token.ASSIGN || p.tok == token.DEFINE { // RecvStmt with assignment if len(lhs) > 2 { p.errorExpected(lhs[0].Pos(), "1 or 2 expressions") // continue with first two expressions lhs = lhs[0:2] } p.next() rhs = p.parseExpr() } else { // rhs must be single receive operation if len(lhs) > 1 { p.errorExpected(lhs[0].Pos(), "1 expression") // continue with first expression } rhs = lhs[0] lhs = nil // there is no lhs } if x, isUnary := rhs.(*ast.UnaryExpr); !isUnary || x.Op != token.ARROW { p.errorExpected(rhs.Pos(), "send or receive operation") rhs = &ast.BadExpr{rhs.Pos(), rhs.End()} } if lhs != nil { comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}} } else { comm = &ast.ExprStmt{rhs} } } } else { p.expect(token.DEFAULT) } colon := p.expect(token.COLON) body := p.parseStmtList() return &ast.CommClause{pos, comm, colon, body} }