feature: add Sizeof and Alignof to unsafe

This commit is contained in:
Nicholas Wiersma
2020-06-22 15:24:04 +02:00
committed by GitHub
parent e00b853971
commit 9627782394
5 changed files with 70 additions and 21 deletions

22
_test/unsafe5.go Normal file
View File

@@ -0,0 +1,22 @@
package main
import (
"fmt"
"unsafe"
)
type S struct {
X int
Y int
Z int
}
func main() {
size := unsafe.Sizeof(S{})
align := unsafe.Alignof(S{})
fmt.Println(size, align)
}
// Output:
// 24 8

30
interp/hooks.go Normal file
View File

@@ -0,0 +1,30 @@
package interp
import "reflect"
const hooksPath = "github.com/containous/yaegi"
// convertFn is the signature of a symbol converter.
type convertFn func(from, to reflect.Type) func(src, dest reflect.Value)
// hooks are external symbol bindings.
type hooks struct {
convert []convertFn
}
func (h *hooks) Parse(m map[string]reflect.Value) {
if con, ok := getConvertFn(m["convert"]); ok {
h.convert = append(h.convert, con)
}
}
func getConvertFn(v reflect.Value) (convertFn, bool) {
if !v.IsValid() {
return nil, false
}
fn, ok := v.Interface().(func(from, to reflect.Type) func(src, dest reflect.Value))
if !ok {
return nil, false
}
return fn, true
}

View File

@@ -96,9 +96,6 @@ func (f *frame) clone() *frame {
}
}
// convertFn is the signature of a symbol converter.
type convertFn func(from, to reflect.Type) func(src, dest reflect.Value)
// Exports stores the map of binary packages per package path.
type Exports map[string]map[string]reflect.Value
@@ -142,7 +139,7 @@ type Interpreter struct {
pkgNames map[string]string // package names, indexed by path
done chan struct{} // for cancellation of channel operations
convert []convertFn // converters from symbols
hooks *hooks // symbol hooks
}
const (
@@ -221,6 +218,7 @@ func New(options Options) *Interpreter {
srcPkg: imports{},
pkgNames: map[string]string{},
rdir: map[string]bool{},
hooks: &hooks{},
}
i.opt.context.GOPATH = options.GoPath
@@ -471,28 +469,15 @@ func (interp *Interpreter) getWrapper(t reflect.Type) reflect.Type {
// they can be used in interpreted code.
func (interp *Interpreter) Use(values Exports) {
for k, v := range values {
if k != "github.com/containous/yaegi" {
interp.binPkg[k] = v
if k == hooksPath {
interp.hooks.Parse(v)
continue
}
if con, ok := extractConverter(v["convert"]); ok {
interp.convert = append(interp.convert, con)
}
interp.binPkg[k] = v
}
}
func extractConverter(v reflect.Value) (convertFn, bool) {
if !v.IsValid() {
return nil, false
}
fn, ok := v.Interface().(func(from, to reflect.Type) func(src, dest reflect.Value))
if !ok {
return nil, false
}
return fn, true
}
// REPL performs a Read-Eval-Print-Loop on input reader.
// Results are printed on output writer.
func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {

View File

@@ -329,7 +329,7 @@ func convert(n *node) {
value = genValue(c)
}
for _, con := range n.interp.convert {
for _, con := range n.interp.hooks.convert {
if c.typ.rtype == nil {
continue
}

View File

@@ -18,6 +18,10 @@ func init() {
Symbols["github.com/containous/yaegi"] = map[string]reflect.Value{
"convert": reflect.ValueOf(convert),
}
// Add builtin functions to unsafe.
Symbols["unsafe"]["Sizeof"] = reflect.ValueOf(sizeof)
Symbols["unsafe"]["Alignof"] = reflect.ValueOf(alignof)
}
func convert(from, to reflect.Type) func(src, dest reflect.Value) {
@@ -46,4 +50,12 @@ func convert(from, to reflect.Type) func(src, dest reflect.Value) {
}
}
func sizeof(i interface{}) uintptr {
return reflect.ValueOf(i).Type().Size()
}
func alignof(i interface{}) uintptr {
return uintptr(reflect.ValueOf(i).Type().Align())
}
//go:generate ../../cmd/goexports/goexports unsafe