Commit f243584d authored by Robert Griesemer's avatar Robert Griesemer

go/*: support for slices with cap: s[:j:k] and s[i:j:k]

Experimental, per rsc's proposal.

R=rsc
CC=golang-dev
https://golang.org/cl/10204043
parent 6bea504b
...@@ -297,6 +297,7 @@ type ( ...@@ -297,6 +297,7 @@ type (
Lbrack token.Pos // position of "[" Lbrack token.Pos // position of "["
Low Expr // begin of slice range; or nil Low Expr // begin of slice range; or nil
High Expr // end of slice range; or nil High Expr // end of slice range; or nil
Max Expr // maximum capacity of slice; or nil
Rbrack token.Pos // position of "]" Rbrack token.Pos // position of "]"
} }
......
...@@ -122,6 +122,9 @@ func Walk(v Visitor, node Node) { ...@@ -122,6 +122,9 @@ func Walk(v Visitor, node Node) {
if n.High != nil { if n.High != nil {
Walk(v, n.High) Walk(v, n.High)
} }
if n.Max != nil {
Walk(v, n.Max)
}
case *TypeAssertExpr: case *TypeAssertExpr:
Walk(v, n.X) Walk(v, n.X)
......
...@@ -1170,25 +1170,31 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr { ...@@ -1170,25 +1170,31 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
lbrack := p.expect(token.LBRACK) lbrack := p.expect(token.LBRACK)
p.exprLev++ p.exprLev++
var low, high ast.Expr var index [3]ast.Expr // change the 3 to 2 to disable slice expressions w/ cap
isSlice := false
if p.tok != token.COLON { if p.tok != token.COLON {
low = p.parseRhs() index[0] = p.parseRhs()
} }
if p.tok == token.COLON { ncolons := 0
isSlice = true for p.tok == token.COLON && ncolons < len(index)-1 {
p.next() p.next()
if p.tok != token.RBRACK { ncolons++
high = p.parseRhs() if p.tok != token.COLON && p.tok != token.RBRACK && p.tok != token.EOF {
index[ncolons] = p.parseRhs()
} }
} }
p.exprLev-- p.exprLev--
rbrack := p.expect(token.RBRACK) rbrack := p.expect(token.RBRACK)
if isSlice { if ncolons > 0 {
return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: low, High: high, Rbrack: rbrack} // slice expression
if ncolons == 2 && (index[1] == nil || index[2] == nil) {
// only i is optional in a[i:j:k]
p.error(rbrack, "2nd and 3rd index must be present full slice expression")
}
return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Rbrack: rbrack}
} }
return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: low, Rbrack: rbrack}
return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
} }
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
......
...@@ -33,6 +33,7 @@ var valids = []string{ ...@@ -33,6 +33,7 @@ var valids = []string{
`package p; func f() { if ; true {} };`, `package p; func f() { if ; true {} };`,
`package p; func f() { switch ; {} };`, `package p; func f() { switch ; {} };`,
`package p; func f() { for _ = range "foo" + "bar" {} };`, `package p; func f() { for _ = range "foo" + "bar" {} };`,
`package p; func f() { var s []int; g(s[:], s[i:], s[:j], s[i:j], s[i:j:k], s[:j:k]) };`,
} }
func TestValid(t *testing.T) { func TestValid(t *testing.T) {
...@@ -74,6 +75,15 @@ var invalids = []string{ ...@@ -74,6 +75,15 @@ var invalids = []string{
`package p; func f() { if x := g(); x = /* ERROR "expected '=='" */ 0 {}};`, `package p; func f() { if x := g(); x = /* ERROR "expected '=='" */ 0 {}};`,
`package p; func f() { _ = x = /* ERROR "expected '=='" */ 0 {}};`, `package p; func f() { _ = x = /* ERROR "expected '=='" */ 0 {}};`,
`package p; func f() { _ = 1 == func()int { var x bool; x = x = /* ERROR "expected '=='" */ true; return x }() };`, `package p; func f() { _ = 1 == func()int { var x bool; x = x = /* ERROR "expected '=='" */ true; return x }() };`,
`package p; func f() { var s []int; _ = s[] /* ERROR "expected operand" */ };`,
`package p; func f() { var s []int; _ = s[::: /* ERROR "expected ']'" */ ] };`,
`package p; func f() { var s []int; _ = s[i:j:k: /* ERROR "expected ']'" */ l] };`,
`package p; func f() { var s []int; g(s[::] /* ERROR "index must be present" */) };`,
`package p; func f() { var s []int; g(s[i::] /* ERROR "index must be present" */) };`,
`package p; func f() { var s []int; g(s[i:j:] /* ERROR "index must be present" */) };`,
`package p; func f() { var s []int; g(s[::k] /* ERROR "index must be present" */) };`,
`package p; func f() { var s []int; g(s[:j:] /* ERROR "index must be present" */) };`,
`package p; func f() { var s []int; g(s[i::k] /* ERROR "index must be present" */) };`,
} }
func TestInvalid(t *testing.T) { func TestInvalid(t *testing.T) {
......
...@@ -773,17 +773,25 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { ...@@ -773,17 +773,25 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
// TODO(gri): should treat[] like parentheses and undo one level of depth // TODO(gri): should treat[] like parentheses and undo one level of depth
p.expr1(x.X, token.HighestPrec, 1) p.expr1(x.X, token.HighestPrec, 1)
p.print(x.Lbrack, token.LBRACK) p.print(x.Lbrack, token.LBRACK)
if x.Low != nil { indices := []ast.Expr{x.Low, x.High}
p.expr0(x.Low, depth+1) if x.Max != nil {
indices = append(indices, x.Max)
} }
// blanks around ":" if both sides exist and either side is a binary expression for i, y := range indices {
if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) { if i > 0 {
p.print(blank, token.COLON, blank) // blanks around ":" if both sides exist and either side is a binary expression
} else { // TODO(gri) once we have committed a variant of a[i:j:k] we may want to fine-
p.print(token.COLON) // tune the formatting here
} x := indices[i-1]
if x.High != nil { if depth <= 1 && x != nil && y != nil && (isBinary(x) || isBinary(y)) {
p.expr0(x.High, depth+1) p.print(blank, token.COLON, blank)
} else {
p.print(token.COLON)
}
}
if y != nil {
p.expr0(y, depth+1)
}
} }
p.print(x.Rbrack, token.RBRACK) p.print(x.Rbrack, token.RBRACK)
......
...@@ -114,6 +114,23 @@ func _() { ...@@ -114,6 +114,23 @@ func _() {
x < y || z > 42 x < y || z > 42
} }
// slice expressions with cap
func _() {
_ = x[a:b:c]
_ = x[a:b : c+d]
_ = x[a : b+d : c]
_ = x[a : b+d : c+d]
_ = x[a+d : b:c]
_ = x[a+d : b : c+d]
_ = x[a+d : b+d : c]
_ = x[a+d : b+d : c+d]
_ = x[:b:c]
_ = x[:b : c+d]
_ = x[:b+d : c]
_ = x[:b+d : c+d]
}
func _() { func _() {
_ = a + b _ = a + b
_ = a + b + c _ = a + b + c
......
...@@ -116,6 +116,23 @@ func _() { ...@@ -116,6 +116,23 @@ func _() {
} }
// slice expressions with cap
func _() {
_ = x[a:b:c]
_ = x[a:b:c+d]
_ = x[a:b+d:c]
_ = x[a:b+d:c+d]
_ = x[a+d:b:c]
_ = x[a+d:b:c+d]
_ = x[a+d:b+d:c]
_ = x[a+d:b+d:c+d]
_ = x[:b:c]
_ = x[:b:c+d]
_ = x[:b+d:c]
_ = x[:b+d:c+d]
}
func _() { func _() {
_ = a+b _ = a+b
_ = a+b+c _ = a+b+c
......
...@@ -114,6 +114,23 @@ func _() { ...@@ -114,6 +114,23 @@ func _() {
x < y || z > 42 x < y || z > 42
} }
// slice expressions with cap
func _() {
_ = x[a:b:c]
_ = x[a:b : c+d]
_ = x[a : b+d : c]
_ = x[a : b+d : c+d]
_ = x[a+d : b:c]
_ = x[a+d : b : c+d]
_ = x[a+d : b+d : c]
_ = x[a+d : b+d : c+d]
_ = x[:b:c]
_ = x[:b : c+d]
_ = x[:b+d : c]
_ = x[:b+d : c+d]
}
func _() { func _() {
_ = a + b _ = a + b
_ = a + b + c _ = a + b + c
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment