case *ast.IndexExpr:
walk(&n.X, p, "expr");
walk(&n.Index, p, "expr");
+ case *ast.SliceExpr:
+ walk(&n.X, p, "expr");
+ walk(&n.Index, p, "expr");
if n.End != nil {
walk(&n.End, p, "expr")
}
return ei.compileIdent(a.block, a.constant, callCtx, x.Value)
case *ast.IndexExpr:
- if x.End != nil {
- arr := a.compile(x.X, false);
- lo := a.compile(x.Index, false);
- hi := a.compile(x.End, false);
- if arr == nil || lo == nil || hi == nil {
- return nil
- }
- 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.SliceExpr:
+ end := x.End;
+ if end == nil {
+ // TODO: set end to len(x.X)
+ panic("unimplemented")
+ }
+ arr := a.compile(x.X, false);
+ lo := a.compile(x.Index, false);
+ hi := a.compile(end, false);
+ if arr == nil || lo == nil || hi == nil {
+ return nil
+ }
+ return ei.compileSliceExpr(arr, lo, hi);
+
case *ast.KeyValueExpr:
goto notimpl
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 {
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
};
func (x *CompositeLit) Pos() token.Position { return x.Type.Pos() }
func (x *SelectorExpr) 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 *CallExpr) Pos() token.Position { return x.Fun.Pos() }
func (x *BinaryExpr) Pos() token.Position { return x.X.Pos() }
func (x *ParenExpr) exprNode() {}
func (x *SelectorExpr) exprNode() {}
func (x *IndexExpr) exprNode() {}
+func (x *SliceExpr) exprNode() {}
func (x *TypeAssertExpr) exprNode() {}
func (x *CallExpr) exprNode() {}
func (x *StarExpr) exprNode() {}
case *IndexExpr:
Walk(v, n.X);
Walk(v, n.Index);
+
+ case *SliceExpr:
+ Walk(v, n.X);
+ Walk(v, n.Index);
Walk(v, n.End);
case *TypeAssertExpr:
}
-func (p *parser) parseIndex(x ast.Expr) ast.Expr {
+func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
if p.trace {
- defer un(trace(p, "Index"))
+ defer un(trace(p, "IndexOrSlice"))
}
p.expect(token.LBRACK);
p.exprLev++;
- begin := p.parseExpr();
- var end ast.Expr;
+ index := p.parseExpr();
if p.tok == token.COLON {
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.expect(token.RBRACK);
- return &ast.IndexExpr{x, begin, end};
+ return x;
}
case *ast.ParenExpr:
case *ast.SelectorExpr:
case *ast.IndexExpr:
+ case *ast.SliceExpr:
case *ast.TypeAssertExpr:
if t.Type == nil {
// the form X.(type) is only allowed in type switch expressions
case token.PERIOD:
x = p.parseSelectorOrTypeAssertion(p.checkExpr(x))
case token.LBRACK:
- x = p.parseIndex(p.checkExpr(x))
+ x = p.parseIndexOrSlice(p.checkExpr(x))
case token.LPAREN:
x = p.parseCallOrConversion(p.checkExprOrType(x))
case token.LBRACE:
p.print(token.RPAREN);
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.print(token.LBRACK);
p.expr0(x.Index, depth+1, multiLine);
+ p.print(token.RBRACK);
+
+ 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)
+ } else {
+ p.print(token.COLON)
+ }
if x.End != nil {
- // blanks around ":" if either side is a binary expression
- if depth <= 1 && (isBinary(x.Index) || isBinary(x.End)) {
- p.print(blank, token.COLON, blank)
- } else {
- p.print(token.COLON)
- }
- p.expr0(x.End, depth+1, multiLine);
+ p.expr0(x.End, depth+1, multiLine)
}
p.print(token.RBRACK);
_ = 1 + 2*3;
_ = s[1 : 2*3];
_ = 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[len(s):-a];
_ = s[a : len(s)+1];
_ = 1 + 2*3;
_ = s[1 : 2*3];
_ = 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[len(s) : -a];
_ = s[a : len(s)+1];
_ = 1 + 2*3;
_ = s[1 : 2*3];
_ = 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[len(s):-a];
_ = s[a : len(s)+1];