go.tools/go/ssa: support 3-operand x[lo:hi:max] slices.

+ very basic test ($GOROOT/test/slice3.go needs unsafe.Pointer)

LGTM=gri
R=gri
CC=golang-codereviews
https://golang.org/cl/60030043
This commit is contained in:
Alan Donovan 2014-02-05 17:54:51 -05:00
parent c37c5f6f46
commit b3dbe56610
6 changed files with 53 additions and 18 deletions

View File

@ -569,7 +569,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
} }
case *ast.SliceExpr: case *ast.SliceExpr:
var low, high Value var low, high, max Value
var x Value var x Value
switch fn.Pkg.typeOf(e.X).Underlying().(type) { switch fn.Pkg.typeOf(e.X).Underlying().(type) {
case *types.Array: case *types.Array:
@ -586,10 +586,14 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
if e.Low != nil { if e.Low != nil {
low = b.expr(fn, e.Low) low = b.expr(fn, e.Low)
} }
if e.Slice3 {
max = b.expr(fn, e.Max)
}
v := &Slice{ v := &Slice{
X: x, X: x,
Low: low, Low: low,
High: high, High: high,
Max: max,
} }
v.setPos(e.Lbrack) v.setPos(e.Lbrack)
v.setType(fn.Pkg.typeOf(e)) v.setType(fn.Pkg.typeOf(e))

View File

@ -214,7 +214,7 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation {
fr.env[instr] = fr.get(instr.Tuple).(tuple)[instr.Index] fr.env[instr] = fr.get(instr.Tuple).(tuple)[instr.Index]
case *ssa.Slice: case *ssa.Slice:
fr.env[instr] = slice(fr.get(instr.X), fr.get(instr.Low), fr.get(instr.High)) fr.env[instr] = slice(fr.get(instr.X), fr.get(instr.Low), fr.get(instr.High), fr.get(instr.Max))
case *ssa.Return: case *ssa.Return:
switch len(instr.Results) { switch len(instr.Results) {

View File

@ -231,29 +231,44 @@ func zero(t types.Type) value {
panic(fmt.Sprint("zero: unexpected ", t)) panic(fmt.Sprint("zero: unexpected ", t))
} }
// slice returns x[lo:hi]. Either or both of lo and hi may be nil. // slice returns x[lo:hi:max]. Any of lo, hi and max may be nil.
func slice(x, lo, hi value) value { func slice(x, lo, hi, max value) value {
var Len, Cap int
switch x := x.(type) {
case string:
Len = len(x)
case []value:
Len = len(x)
Cap = cap(x)
case *value: // *array
a := (*x).(array)
Len = len(a)
Cap = cap(a)
}
l := 0 l := 0
if lo != nil { if lo != nil {
l = asInt(lo) l = asInt(lo)
} }
h := Len
if hi != nil {
h = asInt(hi)
}
m := Cap
if max != nil {
m = asInt(max)
}
switch x := x.(type) { switch x := x.(type) {
case string: case string:
if hi != nil { return x[l:h]
return x[l:asInt(hi)]
}
return x[l:]
case []value: case []value:
if hi != nil { return x[l:h:m]
return x[l:asInt(hi)]
}
return x[l:]
case *value: // *array case *value: // *array
a := (*x).(array) a := (*x).(array)
if hi != nil { return []value(a)[l:h:m]
return []value(a)[l:asInt(hi)]
}
return []value(a)[l:]
} }
panic(fmt.Sprintf("slice: unexpected X type: %T", x)) panic(fmt.Sprintf("slice: unexpected X type: %T", x))
} }

View File

@ -624,3 +624,15 @@ func init() {
panic(r) panic(r)
} }
} }
// Test of 3-operand x[lo:hi:max] slice.
func init() {
s := []int{0, 1, 2, 3}
lenCapLoHi := func(x []int) [4]int { return [4]int{len(x), cap(x), x[0], x[len(x)-1]} }
if got := lenCapLoHi(s[1:3]); got != [4]int{2, 3, 1, 2} {
panic(got)
}
if got := lenCapLoHi(s[1:3:3]); got != [4]int{2, 2, 1, 2} {
panic(got)
}
}

View File

@ -201,6 +201,10 @@ func (v *Slice) String() string {
if v.High != nil { if v.High != nil {
b.WriteString(relName(v.High, v)) b.WriteString(relName(v.High, v))
} }
if v.Max != nil {
b.WriteString(":")
b.WriteString(relName(v.Max, v))
}
b.WriteString("]") b.WriteString("]")
return b.String() return b.String()
} }

View File

@ -723,8 +723,8 @@ type MakeSlice struct {
// //
type Slice struct { type Slice struct {
register register
X Value // slice, string, or *array X Value // slice, string, or *array
Low, High Value // either may be nil Low, High, Max Value // each may be nil
} }
// The FieldAddr instruction yields the address of Field of *struct X. // The FieldAddr instruction yields the address of Field of *struct X.