Commit b48f7121 authored by Robert Griesemer's avatar Robert Griesemer

Permit omission of hi bound in slices.

R=r, rsc
https://golang.org/cl/157082
parent 61660adc
...@@ -178,6 +178,9 @@ func walk(x interface{}, p *Prog, context string) { ...@@ -178,6 +178,9 @@ func walk(x interface{}, p *Prog, context string) {
case *ast.IndexExpr: case *ast.IndexExpr:
walk(&n.X, p, "expr"); walk(&n.X, p, "expr");
walk(&n.Index, p, "expr"); walk(&n.Index, p, "expr");
case *ast.SliceExpr:
walk(&n.X, p, "expr");
walk(&n.Index, p, "expr");
if n.End != nil { if n.End != nil {
walk(&n.End, p, "expr") walk(&n.End, p, "expr")
} }
......
...@@ -581,20 +581,25 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr { ...@@ -581,20 +581,25 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
return ei.compileIdent(a.block, a.constant, callCtx, x.Value) return ei.compileIdent(a.block, a.constant, callCtx, x.Value)
case *ast.IndexExpr: case *ast.IndexExpr:
if x.End != nil { l, r := a.compile(x.X, false), a.compile(x.Index, false);
if l == nil || r == nil {
return nil
}
return ei.compileIndexExpr(l, r);
case *ast.SliceExpr:
end := x.End;
if end == nil {
// TODO: set end to len(x.X)
panic("unimplemented")
}
arr := a.compile(x.X, false); arr := a.compile(x.X, false);
lo := a.compile(x.Index, false); lo := a.compile(x.Index, false);
hi := a.compile(x.End, false); hi := a.compile(end, false);
if arr == nil || lo == nil || hi == nil { if arr == nil || lo == nil || hi == nil {
return nil return nil
} }
return ei.compileSliceExpr(arr, lo, hi); return ei.compileSliceExpr(arr, lo, hi);
}
l, r := a.compile(x.X, false), a.compile(x.Index, false);
if l == nil || r == nil {
return nil
}
return ei.compileIndexExpr(l, r);
case *ast.KeyValueExpr: case *ast.KeyValueExpr:
goto notimpl goto notimpl
......
...@@ -172,10 +172,16 @@ type ( ...@@ -172,10 +172,16 @@ type (
Sel *Ident; // field selector Sel *Ident; // field selector
}; };
// An IndexExpr node represents an expression followed by an index or slice. // An IndexExpr node represents an expression followed by an index.
IndexExpr struct { IndexExpr struct {
X Expr; // expression X Expr; // expression
Index Expr; // index expression or beginning of slice range Index Expr; // index expression
};
// An SliceExpr node represents an expression followed by slice indices.
SliceExpr struct {
X Expr; // expression
Index Expr; // beginning of slice range
End Expr; // end of slice range; or nil End Expr; // end of slice range; or nil
}; };
...@@ -305,6 +311,7 @@ func (x *FuncLit) Pos() token.Position { return x.Type.Pos() } ...@@ -305,6 +311,7 @@ func (x *FuncLit) Pos() token.Position { return x.Type.Pos() }
func (x *CompositeLit) Pos() token.Position { return x.Type.Pos() } func (x *CompositeLit) Pos() token.Position { return x.Type.Pos() }
func (x *SelectorExpr) Pos() token.Position { return x.X.Pos() } func (x *SelectorExpr) Pos() token.Position { return x.X.Pos() }
func (x *IndexExpr) Pos() token.Position { return x.X.Pos() } func (x *IndexExpr) Pos() token.Position { return x.X.Pos() }
func (x *SliceExpr) Pos() token.Position { return x.X.Pos() }
func (x *TypeAssertExpr) Pos() token.Position { return x.X.Pos() } func (x *TypeAssertExpr) Pos() token.Position { return x.X.Pos() }
func (x *CallExpr) Pos() token.Position { return x.Fun.Pos() } func (x *CallExpr) Pos() token.Position { return x.Fun.Pos() }
func (x *BinaryExpr) Pos() token.Position { return x.X.Pos() } func (x *BinaryExpr) Pos() token.Position { return x.X.Pos() }
...@@ -323,6 +330,7 @@ func (x *CompositeLit) exprNode() {} ...@@ -323,6 +330,7 @@ func (x *CompositeLit) exprNode() {}
func (x *ParenExpr) exprNode() {} func (x *ParenExpr) exprNode() {}
func (x *SelectorExpr) exprNode() {} func (x *SelectorExpr) exprNode() {}
func (x *IndexExpr) exprNode() {} func (x *IndexExpr) exprNode() {}
func (x *SliceExpr) exprNode() {}
func (x *TypeAssertExpr) exprNode() {} func (x *TypeAssertExpr) exprNode() {}
func (x *CallExpr) exprNode() {} func (x *CallExpr) exprNode() {}
func (x *StarExpr) exprNode() {} func (x *StarExpr) exprNode() {}
......
...@@ -129,6 +129,10 @@ func Walk(v Visitor, node interface{}) { ...@@ -129,6 +129,10 @@ func Walk(v Visitor, node interface{}) {
case *IndexExpr: case *IndexExpr:
Walk(v, n.X); Walk(v, n.X);
Walk(v, n.Index); Walk(v, n.Index);
case *SliceExpr:
Walk(v, n.X);
Walk(v, n.Index);
Walk(v, n.End); Walk(v, n.End);
case *TypeAssertExpr: case *TypeAssertExpr:
......
...@@ -962,23 +962,28 @@ func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr { ...@@ -962,23 +962,28 @@ func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
} }
func (p *parser) parseIndex(x ast.Expr) ast.Expr { func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
if p.trace { if p.trace {
defer un(trace(p, "Index")) defer un(trace(p, "IndexOrSlice"))
} }
p.expect(token.LBRACK); p.expect(token.LBRACK);
p.exprLev++; p.exprLev++;
begin := p.parseExpr(); index := p.parseExpr();
var end ast.Expr;
if p.tok == token.COLON { if p.tok == token.COLON {
p.next(); p.next();
end = p.parseExpr(); var end ast.Expr;
if p.tok != token.RBRACK {
end = p.parseExpr()
}
x = &ast.SliceExpr{x, index, end};
} else {
x = &ast.IndexExpr{x, index}
} }
p.exprLev--; p.exprLev--;
p.expect(token.RBRACK); p.expect(token.RBRACK);
return &ast.IndexExpr{x, begin, end}; return x;
} }
...@@ -1072,6 +1077,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { ...@@ -1072,6 +1077,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
case *ast.ParenExpr: case *ast.ParenExpr:
case *ast.SelectorExpr: case *ast.SelectorExpr:
case *ast.IndexExpr: case *ast.IndexExpr:
case *ast.SliceExpr:
case *ast.TypeAssertExpr: case *ast.TypeAssertExpr:
if t.Type == nil { if t.Type == nil {
// the form X.(type) is only allowed in type switch expressions // the form X.(type) is only allowed in type switch expressions
...@@ -1168,7 +1174,7 @@ L: for { ...@@ -1168,7 +1174,7 @@ L: for {
case token.PERIOD: case token.PERIOD:
x = p.parseSelectorOrTypeAssertion(p.checkExpr(x)) x = p.parseSelectorOrTypeAssertion(p.checkExpr(x))
case token.LBRACK: case token.LBRACK:
x = p.parseIndex(p.checkExpr(x)) x = p.parseIndexOrSlice(p.checkExpr(x))
case token.LPAREN: case token.LPAREN:
x = p.parseCallOrConversion(p.checkExprOrType(x)) x = p.parseCallOrConversion(p.checkExprOrType(x))
case token.LBRACE: case token.LBRACE:
......
...@@ -665,17 +665,25 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi ...@@ -665,17 +665,25 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
p.print(token.RPAREN); p.print(token.RPAREN);
case *ast.IndexExpr: 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.expr1(x.X, token.HighestPrec, 1, 0, multiLine);
p.print(token.LBRACK); p.print(token.LBRACK);
p.expr0(x.Index, depth+1, multiLine); p.expr0(x.Index, depth+1, multiLine);
if x.End != nil { p.print(token.RBRACK);
// blanks around ":" if either side is a binary expression
if depth <= 1 && (isBinary(x.Index) || isBinary(x.End)) { 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(token.LBRACK);
p.expr0(x.Index, depth+1, multiLine);
// blanks around ":" if both sides exist and either side is a binary expression
if depth <= 1 && x.End != nil && (isBinary(x.Index) || isBinary(x.End)) {
p.print(blank, token.COLON, blank) p.print(blank, token.COLON, blank)
} else { } else {
p.print(token.COLON) p.print(token.COLON)
} }
p.expr0(x.End, depth+1, multiLine); if x.End != nil {
p.expr0(x.End, depth+1, multiLine)
} }
p.print(token.RBRACK); p.print(token.RBRACK);
......
...@@ -53,6 +53,11 @@ func _() { ...@@ -53,6 +53,11 @@ func _() {
_ = 1 + 2*3; _ = 1 + 2*3;
_ = s[1 : 2*3]; _ = s[1 : 2*3];
_ = s[a : b-c]; _ = s[a : b-c];
_ = s[0:];
_ = s[a+b];
_ = s[a+b:];
_ = a[a<<b+1];
_ = a[a<<b+1:];
_ = s[a+b : len(s)]; _ = s[a+b : len(s)];
_ = s[len(s):-a]; _ = s[len(s):-a];
_ = s[a : len(s)+1]; _ = s[a : len(s)+1];
......
...@@ -53,6 +53,11 @@ func _() { ...@@ -53,6 +53,11 @@ func _() {
_ = 1 + 2*3; _ = 1 + 2*3;
_ = s[1 : 2*3]; _ = s[1 : 2*3];
_ = s[a : b-c]; _ = s[a : b-c];
_ = s[0:];
_ = s[a+b];
_ = s[a+b :];
_ = a[a<<b+1];
_ = a[a<<b+1 :];
_ = s[a+b : len(s)]; _ = s[a+b : len(s)];
_ = s[len(s) : -a]; _ = s[len(s) : -a];
_ = s[a : len(s)+1]; _ = s[a : len(s)+1];
......
...@@ -53,6 +53,11 @@ func _() { ...@@ -53,6 +53,11 @@ func _() {
_ = 1 + 2*3; _ = 1 + 2*3;
_ = s[1 : 2*3]; _ = s[1 : 2*3];
_ = s[a : b-c]; _ = s[a : b-c];
_ = s[0:];
_ = s[a+b];
_ = s[a+b:];
_ = a[a<<b+1];
_ = a[a<<b+1:];
_ = s[a+b : len(s)]; _ = s[a+b : len(s)];
_ = s[len(s):-a]; _ = s[len(s):-a];
_ = s[a : len(s)+1]; _ = s[a : len(s)+1];
......
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