aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim King <taking@google.com>2022-03-06 14:32:59 -0800
committerTim King <taking@google.com>2022-03-09 22:54:42 +0000
commitfd72fd66f6942eba57acf68b91749da38ff16e9b (patch)
tree5bcc14d9ea6c68c6803a999fe642dea99c58bf3d
parentb105aac5705e64187ac8851a26636693404b0ec4 (diff)
downloadgolang-x-tools-fd72fd66f6942eba57acf68b91749da38ff16e9b.tar.gz
go/ssa/interp: adding external functions for tests
Adding additional external functions to be available for go/ssa/interp's testdata. These functions are used by main files in $GOROOT/test/typeparams/*.go Updates golang/go#48525 Change-Id: I80b280e2efb4616d24b50ccf3d2aefa7b486a893 Reviewed-on: https://go-review.googlesource.com/c/tools/+/390294 Reviewed-by: Robert Findley <rfindley@google.com> Run-TryBot: Tim King <taking@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Trust: Tim King <taking@google.com>
-rw-r--r--go/ssa/interp/external.go58
-rw-r--r--go/ssa/interp/testdata/src/fmt/fmt.go44
-rw-r--r--go/ssa/interp/testdata/src/io/io.go5
-rw-r--r--go/ssa/interp/testdata/src/log/log.go15
-rw-r--r--go/ssa/interp/testdata/src/math/math.go2
-rw-r--r--go/ssa/interp/testdata/src/reflect/reflect.go41
-rw-r--r--go/ssa/interp/testdata/src/sort/sort.go5
-rw-r--r--go/ssa/interp/testdata/src/strconv/strconv.go6
-rw-r--r--go/ssa/interp/testdata/src/strings/strings.go17
-rw-r--r--go/ssa/interp/testdata/src/sync/sync.go36
10 files changed, 224 insertions, 5 deletions
diff --git a/go/ssa/interp/external.go b/go/ssa/interp/external.go
index 68ddee318..51b3be0bd 100644
--- a/go/ssa/interp/external.go
+++ b/go/ssa/interp/external.go
@@ -12,6 +12,8 @@ import (
"math"
"os"
"runtime"
+ "sort"
+ "strconv"
"strings"
"time"
"unicode/utf8"
@@ -79,6 +81,7 @@ func init() {
"math.Log": ext۰math۰Log,
"math.Min": ext۰math۰Min,
"math.NaN": ext۰math۰NaN,
+ "math.Sqrt": ext۰math۰Sqrt,
"os.Exit": ext۰os۰Exit,
"os.Getenv": ext۰os۰Getenv,
"reflect.New": ext۰reflect۰New,
@@ -93,10 +96,18 @@ func init() {
"runtime.Goexit": ext۰runtime۰Goexit,
"runtime.Gosched": ext۰runtime۰Gosched,
"runtime.NumCPU": ext۰runtime۰NumCPU,
+ "sort.Float64s": ext۰sort۰Float64s,
+ "sort.Ints": ext۰sort۰Ints,
+ "sort.Strings": ext۰sort۰Strings,
+ "strconv.Atoi": ext۰strconv۰Atoi,
+ "strconv.Itoa": ext۰strconv۰Itoa,
+ "strconv.FormatFloat": ext۰strconv۰FormatFloat,
"strings.Count": ext۰strings۰Count,
+ "strings.EqualFold": ext۰strings۰EqualFold,
"strings.Index": ext۰strings۰Index,
"strings.IndexByte": ext۰strings۰IndexByte,
"strings.Replace": ext۰strings۰Replace,
+ "strings.ToLower": ext۰strings۰ToLower,
"time.Sleep": ext۰time۰Sleep,
"unicode/utf8.DecodeRuneInString": ext۰unicode۰utf8۰DecodeRuneInString,
} {
@@ -179,15 +190,58 @@ func ext۰math۰Log(fr *frame, args []value) value {
return math.Log(args[0].(float64))
}
+func ext۰math۰Sqrt(fr *frame, args []value) value {
+ return math.Sqrt(args[0].(float64))
+}
+
func ext۰runtime۰Breakpoint(fr *frame, args []value) value {
runtime.Breakpoint()
return nil
}
+func ext۰sort۰Ints(fr *frame, args []value) value {
+ x := args[0].([]value)
+ sort.Slice(x, func(i, j int) bool {
+ return x[i].(int) < x[j].(int)
+ })
+ return nil
+}
+func ext۰sort۰Strings(fr *frame, args []value) value {
+ x := args[0].([]value)
+ sort.Slice(x, func(i, j int) bool {
+ return x[i].(string) < x[j].(string)
+ })
+ return nil
+}
+func ext۰sort۰Float64s(fr *frame, args []value) value {
+ x := args[0].([]value)
+ sort.Slice(x, func(i, j int) bool {
+ return x[i].(float64) < x[j].(float64)
+ })
+ return nil
+}
+
+func ext۰strconv۰Atoi(fr *frame, args []value) value {
+ i, e := strconv.Atoi(args[0].(string))
+ if e != nil {
+ return tuple{i, iface{fr.i.runtimeErrorString, e.Error()}}
+ }
+ return tuple{i, iface{}}
+}
+func ext۰strconv۰Itoa(fr *frame, args []value) value {
+ return strconv.Itoa(args[0].(int))
+}
+func ext۰strconv۰FormatFloat(fr *frame, args []value) value {
+ return strconv.FormatFloat(args[0].(float64), args[1].(byte), args[2].(int), args[3].(int))
+}
+
func ext۰strings۰Count(fr *frame, args []value) value {
return strings.Count(args[0].(string), args[1].(string))
}
+func ext۰strings۰EqualFold(fr *frame, args []value) value {
+ return strings.EqualFold(args[0].(string), args[1].(string))
+}
func ext۰strings۰IndexByte(fr *frame, args []value) value {
return strings.IndexByte(args[0].(string), args[1].(byte))
}
@@ -205,6 +259,10 @@ func ext۰strings۰Replace(fr *frame, args []value) value {
return strings.Replace(s, old, new, n)
}
+func ext۰strings۰ToLower(fr *frame, args []value) value {
+ return strings.ToLower(args[0].(string))
+}
+
func ext۰runtime۰GOMAXPROCS(fr *frame, args []value) value {
// Ignore args[0]; don't let the interpreted program
// set the interpreter's GOMAXPROCS!
diff --git a/go/ssa/interp/testdata/src/fmt/fmt.go b/go/ssa/interp/testdata/src/fmt/fmt.go
index 2185eb708..af304029c 100644
--- a/go/ssa/interp/testdata/src/fmt/fmt.go
+++ b/go/ssa/interp/testdata/src/fmt/fmt.go
@@ -1,14 +1,28 @@
package fmt
+import (
+ "errors"
+ "strings"
+)
+
func Sprint(args ...interface{}) string
-func Print(args ...interface{}) {
+func Sprintln(args ...interface{}) string {
+ return Sprint(args...) + "\n"
+}
+
+func Print(args ...interface{}) (int, error) {
+ var n int
for i, arg := range args {
if i > 0 {
print(" ")
+ n++
}
- print(Sprint(arg))
+ msg := Sprint(arg)
+ n += len(msg)
+ print(msg)
}
+ return n, nil
}
func Println(args ...interface{}) {
@@ -17,10 +31,30 @@ func Println(args ...interface{}) {
}
// formatting is too complex to fake
+// handle the bare minimum needed for tests
-func Printf(args ...interface{}) string {
- panic("Printf is not supported")
+func Printf(format string, args ...interface{}) (int, error) {
+ msg := Sprintf(format, args...)
+ print(msg)
+ return len(msg), nil
}
+
func Sprintf(format string, args ...interface{}) string {
- panic("Sprintf is not supported")
+ // handle extremely simple cases that appear in tests.
+ if len(format) == 0 {
+ return ""
+ }
+ switch {
+ case strings.HasPrefix("%v", format) || strings.HasPrefix("%s", format):
+ return Sprint(args[0]) + Sprintf(format[2:], args[1:]...)
+ case !strings.HasPrefix("%", format):
+ return format[:1] + Sprintf(format[1:], args...)
+ default:
+ panic("unsupported format string for testing Sprintf")
+ }
+}
+
+func Errorf(format string, args ...interface{}) error {
+ msg := Sprintf(format, args...)
+ return errors.New(msg)
}
diff --git a/go/ssa/interp/testdata/src/io/io.go b/go/ssa/interp/testdata/src/io/io.go
new file mode 100644
index 000000000..8cde43061
--- /dev/null
+++ b/go/ssa/interp/testdata/src/io/io.go
@@ -0,0 +1,5 @@
+package io
+
+import "errors"
+
+var EOF = errors.New("EOF")
diff --git a/go/ssa/interp/testdata/src/log/log.go b/go/ssa/interp/testdata/src/log/log.go
new file mode 100644
index 000000000..8897c1d21
--- /dev/null
+++ b/go/ssa/interp/testdata/src/log/log.go
@@ -0,0 +1,15 @@
+package log
+
+import (
+ "fmt"
+ "os"
+)
+
+func Println(v ...interface{}) {
+ fmt.Println(v...)
+}
+
+func Fatalln(v ...interface{}) {
+ Println(v...)
+ os.Exit(1)
+}
diff --git a/go/ssa/interp/testdata/src/math/math.go b/go/ssa/interp/testdata/src/math/math.go
index f51e5f572..64fe60c99 100644
--- a/go/ssa/interp/testdata/src/math/math.go
+++ b/go/ssa/interp/testdata/src/math/math.go
@@ -11,3 +11,5 @@ func Float64bits(float64) uint64
func Signbit(x float64) bool {
return Float64bits(x)&(1<<63) != 0
}
+
+func Sqrt(x float64) float64
diff --git a/go/ssa/interp/testdata/src/reflect/reflect.go b/go/ssa/interp/testdata/src/reflect/reflect.go
index f6c4e2794..8a23d272f 100644
--- a/go/ssa/interp/testdata/src/reflect/reflect.go
+++ b/go/ssa/interp/testdata/src/reflect/reflect.go
@@ -2,6 +2,8 @@ package reflect
type Type interface {
String() string
+ Kind() Kind
+ Elem() Type
}
type Value struct {
@@ -9,8 +11,47 @@ type Value struct {
func (Value) String() string
+func (Value) Elem() string
+func (Value) Kind() Kind
+func (Value) Int() int64
+
func SliceOf(Type) Type
func TypeOf(interface{}) Type
func ValueOf(interface{}) Value
+
+type Kind uint
+
+// Constants need to be kept in sync with the actual definitions for comparisons in tests.
+const (
+ Invalid Kind = iota
+ Bool
+ Int
+ Int8
+ Int16
+ Int32
+ Int64
+ Uint
+ Uint8
+ Uint16
+ Uint32
+ Uint64
+ Uintptr
+ Float32
+ Float64
+ Complex64
+ Complex128
+ Array
+ Chan
+ Func
+ Interface
+ Map
+ Pointer
+ Slice
+ String
+ Struct
+ UnsafePointer
+)
+
+const Ptr = Pointer
diff --git a/go/ssa/interp/testdata/src/sort/sort.go b/go/ssa/interp/testdata/src/sort/sort.go
new file mode 100644
index 000000000..d94d6dabe
--- /dev/null
+++ b/go/ssa/interp/testdata/src/sort/sort.go
@@ -0,0 +1,5 @@
+package sort
+
+func Strings(x []string)
+func Ints(x []int)
+func Float64s(x []float64)
diff --git a/go/ssa/interp/testdata/src/strconv/strconv.go b/go/ssa/interp/testdata/src/strconv/strconv.go
new file mode 100644
index 000000000..3f6f8772b
--- /dev/null
+++ b/go/ssa/interp/testdata/src/strconv/strconv.go
@@ -0,0 +1,6 @@
+package strconv
+
+func Itoa(i int) string
+func Atoi(s string) (int, error)
+
+func FormatFloat(float64, byte, int, int) string
diff --git a/go/ssa/interp/testdata/src/strings/strings.go b/go/ssa/interp/testdata/src/strings/strings.go
index dd86dcf4f..4c74f1b82 100644
--- a/go/ssa/interp/testdata/src/strings/strings.go
+++ b/go/ssa/interp/testdata/src/strings/strings.go
@@ -7,3 +7,20 @@ func Index(haystack, needle string) int
func Contains(haystack, needle string) bool {
return Index(haystack, needle) >= 0
}
+
+func HasPrefix(s, prefix string) bool {
+ return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
+}
+
+func EqualFold(s, t string) bool
+func ToLower(s string) string
+
+type Builder struct {
+ s string
+}
+
+func (b *Builder) WriteString(s string) (int, error) {
+ b.s += s
+ return len(s), nil
+}
+func (b *Builder) String() string { return b.s }
diff --git a/go/ssa/interp/testdata/src/sync/sync.go b/go/ssa/interp/testdata/src/sync/sync.go
new file mode 100644
index 000000000..457a670d6
--- /dev/null
+++ b/go/ssa/interp/testdata/src/sync/sync.go
@@ -0,0 +1,36 @@
+package sync
+
+// Rudimentary implementation of a mutex for interp tests.
+type Mutex struct {
+ c chan int // Mutex is held when held c!=nil and is empty. Access is guarded by g.
+}
+
+func (m *Mutex) Lock() {
+ c := ch(m)
+ <-c
+}
+
+func (m *Mutex) Unlock() {
+ c := ch(m)
+ c <- 1
+}
+
+// sequentializes Mutex.c access.
+var g = make(chan int, 1)
+
+func init() {
+ g <- 1
+}
+
+// ch initializes the m.c field if needed and returns it.
+func ch(m *Mutex) chan int {
+ <-g
+ defer func() {
+ g <- 1
+ }()
+ if m.c == nil {
+ m.c = make(chan int, 1)
+ m.c <- 1
+ }
+ return m.c
+}