diff --git a/ast/ast_gop.go b/ast/ast_gop.go index 8ccb2a1c1..da6227a5d 100644 --- a/ast/ast_gop.go +++ b/ast/ast_gop.go @@ -159,6 +159,26 @@ func (*MatrixLit) exprNode() {} // ----------------------------------------------------------------------------- +// A ElemEllipsis node represents a matrix row elements. +type ElemEllipsis struct { + Elt Expr // ellipsis element + Ellipsis token.Pos // position of "..." +} + +// Pos - position of first character belonging to the node. +func (p *ElemEllipsis) Pos() token.Pos { + return p.Elt.Pos() +} + +// End - position of first character immediately after the node. +func (p *ElemEllipsis) End() token.Pos { + return p.Ellipsis + 3 +} + +func (*ElemEllipsis) exprNode() {} + +// ----------------------------------------------------------------------------- + // ErrWrapExpr represents `expr!`, `expr?` or `expr?: defaultValue`. type ErrWrapExpr struct { X Expr diff --git a/parser/_testdata/matrix2/matrix.gop b/parser/_testdata/matrix2/matrix.gop new file mode 100644 index 000000000..1682ebecf --- /dev/null +++ b/parser/_testdata/matrix2/matrix.gop @@ -0,0 +1,5 @@ +echo [ + 1, 2, 3 + row... + 7, 8, 9 +] diff --git a/parser/_testdata/matrix2/parser.expect b/parser/_testdata/matrix2/parser.expect new file mode 100644 index 000000000..9e62b45b9 --- /dev/null +++ b/parser/_testdata/matrix2/parser.expect @@ -0,0 +1,47 @@ +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.ElemEllipsis: + Elt: + ast.Ident: + Name: row + ast.BasicLit: + Kind: INT + Value: 7 + ast.BasicLit: + Kind: INT + Value: 8 + ast.BasicLit: + Kind: INT + Value: 9 + NElt: 3 diff --git a/parser/parser.go b/parser/parser.go index 0df026d17..f2d2fc42b 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -899,6 +899,11 @@ func (p *parser) parseSliceOrMatrixLit(lbrack token.Pos, first ast.Expr) ast.Exp case token.SEMICOLON: mat = append(mat, elts) elts = make([]ast.Expr, 0, len(elts)) + case token.ELLIPSIS: + n := len(elts) + elts[n-1] = &ast.ElemEllipsis{Ellipsis: p.pos, Elt: elts[n-1]} + p.next() + continue default: goto done } @@ -2195,6 +2200,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { p.error(v.opening, msgTupleNotSupported) x = &ast.BadExpr{From: v.opening, To: v.closing} case *ast.EnvExpr: + case *ast.ElemEllipsis: default: // all other nodes are not proper expressions p.errorExpected(x.Pos(), "expression", 3) diff --git a/parser/parser_test.go b/parser/parser_test.go index 46921b00c..c7cc34505 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -20,6 +20,7 @@ import ( "io/fs" "testing" + "github.com/goplus/gop/ast" "github.com/goplus/gop/token" fsx "github.com/qiniu/x/http/fs" ) @@ -313,4 +314,15 @@ func TestParseFieldDecl(t *testing.T) { p.parseFieldDecl(nil) } +func TestCheckExpr(t *testing.T) { + var p parser + p.init(token.NewFileSet(), "/foo/bar.gop", []byte(``), 0) + p.checkExpr(&ast.Ellipsis{}) + p.checkExpr(&ast.ElemEllipsis{}) + p.checkExpr(&ast.StarExpr{}) + p.checkExpr(&ast.IndexListExpr{}) + p.checkExpr(&ast.FuncType{}) + p.checkExpr(&ast.FuncLit{}) +} + // ----------------------------------------------------------------------------- diff --git a/printer/nodes.go b/printer/nodes.go index e043c4829..5b8314490 100644 --- a/printer/nodes.go +++ b/printer/nodes.go @@ -1127,6 +1127,10 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { p.print(x.Name) } + case *ast.ElemEllipsis: + p.expr(x.Elt) + p.print(token.ELLIPSIS) + default: log.Fatalf("unreachable %T\n", x) }