From b3dbe56610e0e7bcaeadfb3cc2ced864abff18e9 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Wed, 5 Feb 2014 17:54:51 -0500 Subject: [PATCH] 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 --- go/ssa/builder.go | 6 ++++- go/ssa/interp/interp.go | 2 +- go/ssa/interp/ops.go | 43 ++++++++++++++++++++---------- go/ssa/interp/testdata/coverage.go | 12 +++++++++ go/ssa/print.go | 4 +++ go/ssa/ssa.go | 4 +-- 6 files changed, 53 insertions(+), 18 deletions(-) diff --git a/go/ssa/builder.go b/go/ssa/builder.go index 0e1a89c8..205ca1bb 100644 --- a/go/ssa/builder.go +++ b/go/ssa/builder.go @@ -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)) diff --git a/go/ssa/interp/interp.go b/go/ssa/interp/interp.go index 5ebb3a7e..58194ef9 100644 --- a/go/ssa/interp/interp.go +++ b/go/ssa/interp/interp.go @@ -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) { diff --git a/go/ssa/interp/ops.go b/go/ssa/interp/ops.go index 4e541de7..5452285a 100644 --- a/go/ssa/interp/ops.go +++ b/go/ssa/interp/ops.go @@ -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)) } diff --git a/go/ssa/interp/testdata/coverage.go b/go/ssa/interp/testdata/coverage.go index 2bf8960d..5921f296 100644 --- a/go/ssa/interp/testdata/coverage.go +++ b/go/ssa/interp/testdata/coverage.go @@ -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) + } +} diff --git a/go/ssa/print.go b/go/ssa/print.go index e2d91742..9634fdba 100644 --- a/go/ssa/print.go +++ b/go/ssa/print.go @@ -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() } diff --git a/go/ssa/ssa.go b/go/ssa/ssa.go index 089e5b44..1b153c97 100644 --- a/go/ssa/ssa.go +++ b/go/ssa/ssa.go @@ -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.