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

View File

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

View File

@ -624,3 +624,15 @@ func init() {
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 {
b.WriteString(relName(v.High, v))
}
if v.Max != nil {
b.WriteString(":")
b.WriteString(relName(v.Max, v))
}
b.WriteString("]")
return b.String()
}

View File

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