start example/test for components access
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
21
examples/components/asm.go
Normal file
21
examples/components/asm.go
Normal 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()
|
||||||
|
}
|
||||||
20
examples/components/components.go
Normal file
20
examples/components/components.go
Normal 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
|
||||||
|
}
|
||||||
10
examples/components/components.s
Normal file
10
examples/components/components.s
Normal 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
|
||||||
15
examples/components/components_test.go
Normal file
15
examples/components/components_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
3
examples/components/stub.go
Normal file
3
examples/components/stub.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package components
|
||||||
|
|
||||||
|
func Add(x uint64, s Struct, y uint64) uint64
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
40
gotypes/components_test.go
Normal file
40
gotypes/components_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user