start example/test for components access

This commit is contained in:
Michael McLoughlin
2018-12-17 20:52:26 -08:00
parent 8282c9b17e
commit 34a3ddefcc
10 changed files with 160 additions and 12 deletions

View File

@@ -6,9 +6,11 @@ import (
"github.com/mmcloughlin/avo" "github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/gotypes" "github.com/mmcloughlin/avo/gotypes"
"github.com/mmcloughlin/avo/reg" "github.com/mmcloughlin/avo/reg"
"golang.org/x/tools/go/packages"
) )
type Context struct { type Context struct {
pkg *packages.Package
file *avo.File file *avo.File
function *avo.Function function *avo.Function
errs []error errs []error
@@ -22,6 +24,25 @@ func NewContext() *Context {
} }
} }
func (c *Context) Package(path string) {
cfg := &packages.Config{
Mode: packages.LoadTypes,
}
pkgs, err := packages.Load(cfg, path)
if err != nil {
c.AddError(err)
return
}
pkg := pkgs[0]
if len(pkg.Errors) > 0 {
for _, err := range pkg.Errors {
c.AddError(err)
}
return
}
c.pkg = pkg
}
func (c *Context) Function(name string) { func (c *Context) Function(name string) {
c.function = avo.NewFunction(name) c.function = avo.NewFunction(name)
c.file.Functions = append(c.file.Functions, c.function) c.file.Functions = append(c.file.Functions, c.function)
@@ -32,7 +53,7 @@ func (c *Context) Signature(s *gotypes.Signature) {
} }
func (c *Context) SignatureExpr(expr string) { func (c *Context) SignatureExpr(expr string) {
s, err := gotypes.ParseSignature(expr) s, err := gotypes.ParseSignatureInPackage(c.pkg.Types, expr)
if err != nil { if err != nil {
c.AddError(err) c.AddError(err)
return return

View File

@@ -14,6 +14,8 @@ import (
// ctx provides a global build context. // ctx provides a global build context.
var ctx = NewContext() var ctx = NewContext()
func Package(path string) { ctx.Package(path) }
func TEXT(name, signature string) { func TEXT(name, signature string) {
ctx.Function(name) ctx.Function(name)
ctx.SignatureExpr(signature) ctx.SignatureExpr(signature)

View File

@@ -0,0 +1,21 @@
// +build ignore
package main
import (
. "github.com/mmcloughlin/avo/build"
)
func main() {
Package("github.com/mmcloughlin/avo/examples/components")
// Add confirms that we correctly deduce the packing of Struct.
TEXT("Add", "func(x uint64, s Struct, y uint64) uint64")
x := Load(Param("x"), GP64v())
y := Load(Param("y"), GP64v())
ADDQ(x, y)
Store(y, ReturnIndex(0))
RET()
Generate()
}

View File

@@ -0,0 +1,20 @@
package components
type Struct struct {
Byte byte
Uint32 uint32
Uint64 uint64
Float32 float32
Float64 float64
String string
Slice []Sub
Array [5]Sub
Complex64 complex64
Complex128 complex128
}
type Sub struct {
A uint64
B [3]byte
C uint16
}

View File

@@ -0,0 +1,10 @@
#include "textflag.h"
// func Add(x uint64, s Struct, y uint64) uint64
TEXT ·Add(SB),0,$0-200
MOVQ x(FP), AX
MOVQ y+184(FP), CX
ADDQ AX, CX
MOVQ CX, ret+192(FP)
RET

View File

@@ -0,0 +1,15 @@
package components
import (
"testing"
"testing/quick"
)
//go:generate go run asm.go -out components.s -stubs stub.go
func TestAdd(t *testing.T) {
expect := func(x uint64, s Struct, y uint64) uint64 { return x + y }
if err := quick.CheckEqual(Add, expect, nil); err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,3 @@
package components
func Add(x uint64, s Struct, y uint64) uint64

View File

@@ -56,12 +56,13 @@ func NewComponentFromVar(v *types.Var, offset int) Component {
} }
func (c *component) Resolve() (*Basic, error) { func (c *component) Resolve() (*Basic, error) {
if !isprimitive(c.typ) { b := toprimitive(c.typ)
if b == nil {
return nil, errors.New("component is not primitive") return nil, errors.New("component is not primitive")
} }
return &Basic{ return &Basic{
Addr: operand.NewParamAddr(c.name, c.offset), Addr: operand.NewParamAddr(c.name, c.offset),
Type: c.typ.(*types.Basic), Type: b,
}, nil }, nil
} }
@@ -181,8 +182,17 @@ func complextofloat(t types.Type) types.Type {
panic("bad") panic("bad")
} }
// isprimitive returns true if the type cannot be broken into components. // toprimitive determines whether t is primitive (cannot be reduced into
func isprimitive(t types.Type) bool { // components). If it is, it returns the basic type for t, otherwise returns
b, ok := t.(*types.Basic) // nil.
return ok && (b.Info()&(types.IsString|types.IsComplex)) == 0 func toprimitive(t types.Type) *types.Basic {
switch b := t.(type) {
case *types.Basic:
if (b.Info() & (types.IsString | types.IsComplex)) == 0 {
return b
}
case *types.Pointer:
return types.Typ[types.Uintptr]
}
return nil
} }

View File

@@ -0,0 +1,40 @@
package gotypes
import (
"go/types"
"testing"
)
func TestBasicKindsArePrimitive(t *testing.T) {
kinds := []types.BasicKind{
types.Bool,
types.Int,
types.Int8,
types.Int16,
types.Int32,
types.Int64,
types.Uint,
types.Uint8,
types.Uint16,
types.Uint32,
types.Uint64,
types.Uintptr,
types.Float32,
types.Float64,
}
for _, k := range kinds {
AssertPrimitive(t, types.Typ[k])
}
}
func TestPointersArePrimitive(t *testing.T) {
typ := types.NewPointer(types.Typ[types.Uint32])
AssertPrimitive(t, typ)
}
func AssertPrimitive(t *testing.T, typ types.Type) {
c := NewComponent("primitive", typ, 0)
if _, err := c.Resolve(); err != nil {
t.Errorf("expected type %s to be primitive: got error '%s'", typ, err)
}
}

View File

@@ -10,13 +10,15 @@ import (
) )
type Signature struct { type Signature struct {
pkg *types.Package
sig *types.Signature sig *types.Signature
params *Tuple params *Tuple
results *Tuple results *Tuple
} }
func NewSignature(sig *types.Signature) *Signature { func NewSignature(pkg *types.Package, sig *types.Signature) *Signature {
s := &Signature{ s := &Signature{
pkg: pkg,
sig: sig, sig: sig,
} }
s.init() s.init()
@@ -24,11 +26,15 @@ func NewSignature(sig *types.Signature) *Signature {
} }
func NewSignatureVoid() *Signature { func NewSignatureVoid() *Signature {
return NewSignature(types.NewSignature(nil, nil, nil, false)) return NewSignature(nil, types.NewSignature(nil, nil, nil, false))
} }
func ParseSignature(expr string) (*Signature, error) { func ParseSignature(expr string) (*Signature, error) {
tv, err := types.Eval(token.NewFileSet(), nil, token.NoPos, expr) return ParseSignatureInPackage(nil, expr)
}
func ParseSignatureInPackage(pkg *types.Package, expr string) (*Signature, error) {
tv, err := types.Eval(token.NewFileSet(), pkg, token.NoPos, expr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -39,7 +45,7 @@ func ParseSignature(expr string) (*Signature, error) {
if !ok { if !ok {
return nil, errors.New("provided type is not a function signature") return nil, errors.New("provided type is not a function signature")
} }
return NewSignature(s), nil return NewSignature(pkg, s), nil
} }
func (s *Signature) Params() *Tuple { return s.params } func (s *Signature) Params() *Tuple { return s.params }
@@ -50,7 +56,7 @@ func (s *Signature) Bytes() int { return s.Params().Bytes() + s.Results().Bytes(
func (s *Signature) String() string { func (s *Signature) String() string {
var buf bytes.Buffer var buf bytes.Buffer
types.WriteSignature(&buf, s.sig, nil) types.WriteSignature(&buf, s.sig, types.RelativeTo(s.pkg))
return buf.String() return buf.String()
} }