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>
This commit is contained in:
Tim King 2022-03-06 14:32:59 -08:00
parent b105aac570
commit fd72fd66f6
10 changed files with 224 additions and 5 deletions

View File

@ -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!

View File

@ -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)
}

5
go/ssa/interp/testdata/src/io/io.go vendored Normal file
View File

@ -0,0 +1,5 @@
package io
import "errors"
var EOF = errors.New("EOF")

15
go/ssa/interp/testdata/src/log/log.go vendored Normal file
View File

@ -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)
}

View File

@ -11,3 +11,5 @@ func Float64bits(float64) uint64
func Signbit(x float64) bool {
return Float64bits(x)&(1<<63) != 0
}
func Sqrt(x float64) float64

View File

@ -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

View File

@ -0,0 +1,5 @@
package sort
func Strings(x []string)
func Ints(x []int)
func Float64s(x []float64)

View File

@ -0,0 +1,6 @@
package strconv
func Itoa(i int) string
func Atoi(s string) (int, error)
func FormatFloat(float64, byte, int, int) string

View File

@ -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 }

36
go/ssa/interp/testdata/src/sync/sync.go vendored Normal file
View File

@ -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
}