diff --git a/ast/ast_gop.go b/ast/ast_gop.go index 251716a4e..8ccb2a1c1 100644 --- a/ast/ast_gop.go +++ b/ast/ast_gop.go @@ -118,7 +118,7 @@ func (*EnvExpr) exprNode() {} // A SliceLit node represents a slice literal. type SliceLit struct { Lbrack token.Pos // position of "[" - Elts []Expr // list of composite elements; or nil + Elts []Expr // list of slice elements; or nil Rbrack token.Pos // position of "]" Incomplete bool // true if (source) expressions are missing in the Elts list } @@ -137,6 +137,28 @@ func (*SliceLit) exprNode() {} // ----------------------------------------------------------------------------- +// A MatrixLit node represents a matrix literal. +type MatrixLit struct { + Lbrack token.Pos // position of "[" + Elts [][]Expr // list of matrix elements + Rbrack token.Pos // position of "]" + Incomplete bool // true if (source) expressions are missing in the Elts list +} + +// Pos - position of first character belonging to the node. +func (p *MatrixLit) Pos() token.Pos { + return p.Lbrack +} + +// End - position of first character immediately after the node. +func (p *MatrixLit) End() token.Pos { + return p.Rbrack + 1 +} + +func (*MatrixLit) exprNode() {} + +// ----------------------------------------------------------------------------- + // ErrWrapExpr represents `expr!`, `expr?` or `expr?: defaultValue`. type ErrWrapExpr struct { X Expr diff --git a/parser/_nofmt/matrix1/matrix.gop b/parser/_nofmt/matrix1/matrix.gop new file mode 100644 index 000000000..3b393bd11 --- /dev/null +++ b/parser/_nofmt/matrix1/matrix.gop @@ -0,0 +1,3 @@ +echo [ + 1, 2, 3 + 4, 5, 6 ] diff --git a/parser/_nofmt/matrix1/parser.expect b/parser/_nofmt/matrix1/parser.expect new file mode 100644 index 000000000..ac04e453d --- /dev/null +++ b/parser/_nofmt/matrix1/parser.expect @@ -0,0 +1,43 @@ +package main + +file matrix.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: echo + Args: + ast.MatrixLit: + Elts: + ast.BasicLit: + Kind: INT + Value: 1 + ast.BasicLit: + Kind: INT + Value: 2 + ast.BasicLit: + Kind: INT + Value: 3 + ast.BasicLit: + Kind: INT + Value: 4 + ast.BasicLit: + Kind: INT + Value: 5 + ast.BasicLit: + Kind: INT + Value: 6 + NElt: 2 diff --git a/parser/_testdata/embedded1/embtype.gop b/parser/_testdata/embedded1/embtype.gop new file mode 100644 index 000000000..f34f7c63d --- /dev/null +++ b/parser/_testdata/embedded1/embtype.gop @@ -0,0 +1,3 @@ +type T struct { + abc.E +} diff --git a/parser/_testdata/embedded1/parser.expect b/parser/_testdata/embedded1/parser.expect new file mode 100644 index 000000000..8786d354f --- /dev/null +++ b/parser/_testdata/embedded1/parser.expect @@ -0,0 +1,24 @@ +package main + +file embtype.gop +ast.GenDecl: + Tok: type + Specs: + ast.TypeSpec: + Name: + ast.Ident: + Name: T + Type: + ast.StructType: + Fields: + ast.FieldList: + List: + ast.Field: + Type: + ast.SelectorExpr: + X: + ast.Ident: + Name: abc + Sel: + ast.Ident: + Name: E diff --git a/parser/_testdata/matrix1/matrix.gop b/parser/_testdata/matrix1/matrix.gop new file mode 100644 index 000000000..b46adba77 --- /dev/null +++ b/parser/_testdata/matrix1/matrix.gop @@ -0,0 +1,4 @@ +echo [ + 1, 2, 3 + 4, 5, 6 +] diff --git a/parser/_testdata/matrix1/parser.expect b/parser/_testdata/matrix1/parser.expect new file mode 100644 index 000000000..ac04e453d --- /dev/null +++ b/parser/_testdata/matrix1/parser.expect @@ -0,0 +1,43 @@ +package main + +file matrix.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: echo + Args: + ast.MatrixLit: + Elts: + ast.BasicLit: + Kind: INT + Value: 1 + ast.BasicLit: + Kind: INT + Value: 2 + ast.BasicLit: + Kind: INT + Value: 3 + ast.BasicLit: + Kind: INT + Value: 4 + ast.BasicLit: + Kind: INT + Value: 5 + ast.BasicLit: + Kind: INT + Value: 6 + NElt: 2 diff --git a/parser/parser.go b/parser/parser.go index e6be3a427..0df026d17 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -824,7 +824,7 @@ func (p *parser) parseArrayTypeOrSliceLit(state int, slice ast.Expr) (expr ast.E case stateArrayTypeOrSliceLit: switch p.tok { case token.COMMA: // [a, b, c, d ...] - sliceLit := p.parseSliceLit(lbrack, len) + sliceLit := p.parseSliceOrMatrixLit(lbrack, len) p.exprLev-- return sliceLit, resultSliceLit case token.FOR: // [expr for k, v <- container if cond] @@ -887,20 +887,35 @@ func (p *parser) parseArrayTypeOrSliceLit(state int, slice ast.Expr) (expr ast.E return &ast.ArrayType{Lbrack: lbrack, Len: len, Elt: elt}, resultArrayType } -func (p *parser) parseSliceLit(lbrack token.Pos, len ast.Expr) ast.Expr { +// [first, ...] +// [first, a2, a2, ...; b1, b2, b3, ...] +func (p *parser) parseSliceOrMatrixLit(lbrack token.Pos, first ast.Expr) ast.Expr { + var mat [][]ast.Expr elts := make([]ast.Expr, 1, 8) - elts[0] = len - for p.tok == token.COMMA { + elts[0] = first + for { + switch p.tok { + case token.COMMA: + case token.SEMICOLON: + mat = append(mat, elts) + elts = make([]ast.Expr, 0, len(elts)) + default: + goto done + } p.next() if p.tok != token.RBRACK { elt := p.parseRHS() elts = append(elts, elt) } } +done: rbrack := p.expect(token.RBRACK) - if debugParseOutput { - log.Printf("ast.SliceLit{Elts: %v}\n", elts) + if mat != nil { + if len(elts) > 0 { + mat = append(mat, elts) + } + return &ast.MatrixLit{Lbrack: lbrack, Elts: mat, Rbrack: rbrack} } return &ast.SliceLit{Lbrack: lbrack, Elts: elts, Rbrack: rbrack} } diff --git a/parser/parsertest/parsertest.go b/parser/parsertest/parsertest.go index 081d233ab..def8c1330 100644 --- a/parser/parsertest/parsertest.go +++ b/parser/parsertest/parsertest.go @@ -84,6 +84,9 @@ func FprintNode(w io.Writer, lead string, v interface{}, prefix, indent string) FprintNode(w, fmt.Sprintf("%s%v:\n", prefix, sf.Name), sfv, prefix+indent, indent) } } + if m, ok := v.(*ast.MatrixLit); ok { + fmt.Fprintf(w, "%sNElt: %d\n", prefix, len(m.Elts)) + } } else if lit, ok := v.(*ast.StringLitEx); ok { fmt.Fprintf(w, "%sExtra:\n", prefix) prefix += indent diff --git a/printer/nodes.go b/printer/nodes.go index 881aa6f3b..e043c4829 100644 --- a/printer/nodes.go +++ b/printer/nodes.go @@ -968,6 +968,24 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { p.print(indent, unindent, mode, x.Rbrace, token.RBRACE, mode) p.level-- + case *ast.MatrixLit: + p.level++ + p.print(x.Lbrack, token.LBRACK, newline, indent) + var last = len(x.Elts) - 1 + var incomplete bool + for i, elts := range x.Elts { + if i == last { + incomplete = x.Incomplete + } + p.exprList(elts[0].Pos(), elts, 1, 0, elts[len(elts)-1].End(), incomplete) + p.print(newline) + } + mode := noExtraLinebreak | noExtraBlank + // need the initial indent to print lone comments with + // the proper level of indentation + p.print(unindent, mode, x.Rbrack, token.RBRACK, mode) + p.level-- + case *ast.Ellipsis: p.print(token.ELLIPSIS) if x.Elt != nil { @@ -1034,7 +1052,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { p.print(token.LBRACK) p.expr0(x.Elt, depth+1) p.print(blank) - p.listForPhrase(x.Lpos, x.Fors, depth, x.Rpos) + p.listForPhrase(x.Fors) p.print(token.RBRACK) default: // {...} p.print(token.LBRACE) @@ -1048,7 +1066,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { } p.print(blank) } - p.listForPhrase(x.Lpos, x.Fors, depth, x.Rpos) + p.listForPhrase(x.Fors) p.print(token.RBRACE) } case *ast.ErrWrapExpr: @@ -1114,7 +1132,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { } } -func (p *printer) listForPhrase(prev0 token.Pos, list []*ast.ForPhrase, depth int, next0 token.Pos) { +func (p *printer) listForPhrase(list []*ast.ForPhrase) { for i, x := range list { if i > 0 { p.print(blank) @@ -1906,6 +1924,7 @@ func (p *printer) funcBody(headerSize int, sep whiteSpace, b *ast.BlockStmt) { // by sep. Otherwise the block's opening "{" is printed on the current line, followed by // lines for the block's statements and its closing "}". func (p *printer) funcBodyUnnamed(headerSize int, sep whiteSpace, b *ast.BlockStmt) { + _, _ = headerSize, sep if b == nil { return }