diff --git a/parser/_testdata/cmdlinestyle6/cmd.gop b/parser/_testdata/cmdlinestyle6/cmd.gop new file mode 100644 index 000000000..126b37c52 --- /dev/null +++ b/parser/_testdata/cmdlinestyle6/cmd.gop @@ -0,0 +1 @@ +println (1+2i,2) diff --git a/parser/_testdata/cmdlinestyle6/parser.expect b/parser/_testdata/cmdlinestyle6/parser.expect new file mode 100644 index 000000000..dcdefb1d8 --- /dev/null +++ b/parser/_testdata/cmdlinestyle6/parser.expect @@ -0,0 +1,35 @@ +package main + +file cmd.gop +noEntrypoint +ast.FuncDecl: + Name: + ast.Ident: + Name: main + Type: + ast.FuncType: + Params: + ast.FieldList: + Body: + ast.BlockStmt: + List: + ast.ExprStmt: + X: + ast.CallExpr: + Fun: + ast.Ident: + Name: println + Args: + ast.BinaryExpr: + X: + ast.BasicLit: + Kind: INT + Value: 1 + Op: + + Y: + ast.BasicLit: + Kind: IMAG + Value: 2i + ast.BasicLit: + Kind: INT + Value: 2 diff --git a/parser/parser.go b/parser/parser.go index aeb337604..3ba835749 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -688,10 +688,10 @@ func (p *parser) parseExprList(lhs, allowCmd bool) (list []ast.Expr) { defer un(trace(p, "ExpressionList")) } - list = append(list, p.checkExpr(p.parseExpr(lhs, allowCmd, false))) + list = append(list, p.checkExpr(p.parseExpr(lhs, false, allowCmd, false))) for p.tok == token.COMMA { p.next() - list = append(list, p.checkExpr(p.parseExpr(lhs, false, false))) + list = append(list, p.checkExpr(p.parseExpr(lhs, false, false, false))) } return } @@ -1406,21 +1406,21 @@ func (p *parser) parseOperand(lhs, allowTuple, allowCmd bool) ast.Expr { p.next() if allowTuple && p.tok == token.RPAREN { // () => expr p.next() - return &tupleExpr{} + return &tupleExpr{Opening: lparen, Closing: p.pos} } p.exprLev++ - x := p.parseRHSOrType() // types may be parenthesized: (some type) + x := p.parseRHSOrType(false) // types may be parenthesized: (some type) if allowTuple && p.tok == token.COMMA { // (x, y, ...) => expr - items := make([]*ast.Ident, 1, 2) - items[0] = p.toIdent(x) + items := make([]ast.Expr, 1, 2) + items[0] = x for p.tok == token.COMMA { p.next() - items = append(items, p.parseIdent()) + items = append(items, p.parseRHSOrType(false)) } p.exprLev-- p.expect(token.RPAREN) - return &tupleExpr{items: items} + return &tupleExpr{Opening: lparen, Items: items, Closing: p.pos} } p.exprLev-- rparen := p.expect(token.RPAREN) @@ -1568,7 +1568,6 @@ func (p *parser) parseCallOrConversion(fun ast.Expr, isCmd bool) *ast.CallExpr { if p.trace { defer un(trace(p, "CallOrConversion")) } - var lparen, rparen token.Pos var endTok token.Token if isCmd { @@ -1580,7 +1579,14 @@ func (p *parser) parseCallOrConversion(fun ast.Expr, isCmd bool) *ast.CallExpr { var list []ast.Expr var ellipsis token.Pos for p.tok != endTok && p.tok != token.EOF && !ellipsis.IsValid() { - list = append(list, p.parseRHSOrType()) // builtins may expect a type: make(some type, ...) + expr := p.parseRHSOrType(isCmd && len(list) == 0) + if tuple, ok := expr.(*tupleExpr); ok { + list = tuple.Items + rparen = tuple.Closing + isCmd = false + break + } + list = append(list, expr) // builtins may expect a type: make(some type, ...) if p.tok == token.ELLIPSIS { ellipsis = p.pos p.next() @@ -1600,7 +1606,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr, isCmd bool) *ast.CallExpr { var noParenEnd token.Pos if isCmd { noParenEnd = p.pos - } else { + } else if rparen == token.NoPos { rparen = p.expectClosing(token.RPAREN, "argument list") } if debugParseOutput { @@ -1635,7 +1641,7 @@ func (p *parser) parseValue(keyOk bool) ast.Expr { // undeclared; or b) it is a struct field. In the former case, the type // checker can do a top-level lookup, and in the latter case it will do // a separate field lookup. - x := p.checkExpr(p.parseExpr(keyOk, false, false)) + x := p.checkExpr(p.parseExpr(keyOk, false, false, false)) if keyOk { if p.tok == token.COLON { // Try to resolve the key but don't collect it @@ -1859,6 +1865,9 @@ func (p *parser) parsePrimaryExpr(lhs, allowTuple, allowCmd bool) ast.Expr { } x := p.parseOperand(lhs, allowTuple, allowCmd) + if _, ok := x.(*tupleExpr); ok { + return x + } L: for { switch p.tok { @@ -1898,6 +1907,9 @@ L: } isCmd := allowCmd && x.End() != p.pos // println () x = p.parseCallOrConversion(p.checkExprOrType(x), isCmd) + if isCmd && !x.(*ast.CallExpr).IsCommand() { + allowCmd = false + } case token.LBRACE: // { if allowCmd && x.End() != p.pos { // println {} x = p.parseCallOrConversion(p.checkExprOrType(x), true) @@ -2024,6 +2036,9 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int, allowTuple, allowCmd bool) } x := p.parseUnaryExpr(lhs, allowTuple, allowCmd) + if _, ok := x.(*tupleExpr); ok { + return x + } for { op, oprec := p.tokPrec() if oprec < prec1 { @@ -2065,10 +2080,12 @@ func (p *parser) parseRangeExpr(allowCmd bool) ast.Expr { type tupleExpr struct { ast.Expr - items []*ast.Ident + Opening token.Pos + Items []ast.Expr + Closing token.Pos } -func (p *parser) parseLambdaExpr(allowCmd, allowRangeExpr bool) ast.Expr { +func (p *parser) parseLambdaExpr(allowTuple bool, allowCmd, allowRangeExpr bool) ast.Expr { var x ast.Expr var first = p.pos if p.tok != token.RARROW { @@ -2089,7 +2106,7 @@ func (p *parser) parseLambdaExpr(allowCmd, allowRangeExpr bool) ast.Expr { rhsHasParen = true p.next() for { - item := p.parseExpr(false, false, false) + item := p.parseExpr(false, false, false, false) rhs = append(rhs, item) if p.tok != token.COMMA { break @@ -2100,7 +2117,7 @@ func (p *parser) parseLambdaExpr(allowCmd, allowRangeExpr bool) ast.Expr { case token.LBRACE: // { body = p.parseBlockStmt() default: - rhs = []ast.Expr{p.parseExpr(false, false, false)} + rhs = []ast.Expr{p.parseExpr(false, false, false, false)} } var lhs []*ast.Ident if x != nil { @@ -2108,7 +2125,11 @@ func (p *parser) parseLambdaExpr(allowCmd, allowRangeExpr bool) ast.Expr { retry: switch v := e.(type) { case *tupleExpr: - lhs, lhsHasParen = v.items, true + items := make([]*ast.Ident, len(v.Items), len(v.Items)) + for i, item := range v.Items { + items[i] = p.toIdent(item) + } + lhs, lhsHasParen = items, true case *ast.ParenExpr: e, lhsHasParen = v.X, true goto retry @@ -2138,8 +2159,10 @@ func (p *parser) parseLambdaExpr(allowCmd, allowRangeExpr bool) ast.Expr { RhsHasParen: rhsHasParen, } } - if _, ok := x.(*tupleExpr); ok { - panic("TODO: tupleExpr") + if !allowTuple { + if tuple, ok := x.(*tupleExpr); ok { + p.error(tuple.Opening, "tuple is not supported") + } } return x } @@ -2148,14 +2171,14 @@ func (p *parser) parseLambdaExpr(allowCmd, allowRangeExpr bool) ast.Expr { // The result may be a type or even a raw type ([...]int). Callers must // check the result (using checkExpr or checkExprOrType), depending on // context. -func (p *parser) parseExpr(lhs, allowCmd, allowRangeExpr bool) ast.Expr { +func (p *parser) parseExpr(lhs, allowTuple, allowCmd, allowRangeExpr bool) ast.Expr { if p.trace { defer un(trace(p, "Expression")) } if lhs { return p.parseBinaryExpr(true, token.LowestPrec+1, false, allowCmd) } - return p.parseLambdaExpr(allowCmd, allowRangeExpr) + return p.parseLambdaExpr(allowTuple, allowCmd, allowRangeExpr) } func (p *parser) parseRHS() ast.Expr { @@ -2165,15 +2188,15 @@ func (p *parser) parseRHS() ast.Expr { func (p *parser) parseRHSEx(allowRangeExpr bool) ast.Expr { old := p.inRHS p.inRHS = true - x := p.checkExpr(p.parseExpr(false, false, allowRangeExpr)) + x := p.checkExpr(p.parseExpr(false, false, false, allowRangeExpr)) p.inRHS = old return x } -func (p *parser) parseRHSOrType() ast.Expr { +func (p *parser) parseRHSOrType(allowTuple bool) ast.Expr { old := p.inRHS p.inRHS = true - x := p.checkExprOrType(p.parseExpr(false, false, false)) + x := p.checkExprOrType(p.parseExpr(false, allowTuple, false, false)) p.inRHS = old return x } @@ -2275,7 +2298,7 @@ func (p *parser) parseSimpleStmt(mode int, allowCmd bool) (ast.Stmt, bool) { } func (p *parser) parseCallExpr(callType string) *ast.CallExpr { - x := p.parseRHSOrType() // could be a conversion: (some type)(x) + x := p.parseRHSOrType(false) // could be a conversion: (some type)(x) if call, isCall := x.(*ast.CallExpr); isCall { return call } @@ -2740,13 +2763,13 @@ func (p *parser) parseForPhrases() (phrases []*ast.ForPhrase) { func (p *parser) parseForPhraseStmtPart(lhs []ast.Expr) *ast.ForPhraseStmt { tokPos := p.expect(token.ARROW) // <- - x := p.parseExpr(false, false, true) + x := p.parseExpr(false, false, false, true) var cond ast.Expr var ifPos token.Pos if p.tok == token.IF || p.tok == token.COMMA { ifPos = p.pos p.next() - cond = p.parseExpr(false, false, false) + cond = p.parseExpr(false, false, false, false) } stmt := &ast.ForPhraseStmt{ForPhrase: &ast.ForPhrase{TokPos: tokPos, X: x, IfPos: ifPos, Cond: cond}} @@ -2790,7 +2813,7 @@ func (p *parser) parseForPhrase() *ast.ForPhrase { // for k, v <- container if c } tokPos := p.expect(token.ARROW) // <- container - x := p.parseExpr(false, false, true) + x := p.parseExpr(false, false, false, true) var init ast.Stmt var cond ast.Expr var ifPos token.Pos