337 lines
6.3 KiB
Go
337 lines
6.3 KiB
Go
package abi
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
type Kind uint8
|
|
|
|
const (
|
|
Void Kind = iota
|
|
Bool
|
|
Int
|
|
Float
|
|
String
|
|
Vec2
|
|
Vec3
|
|
Color
|
|
Quat
|
|
Rect
|
|
Transform2D
|
|
Transform3D
|
|
NodeRef
|
|
AssetRef
|
|
ComponentRef
|
|
Enum
|
|
Struct
|
|
Slice
|
|
Coroutine
|
|
Connection
|
|
ScriptRef
|
|
kindCount
|
|
)
|
|
|
|
var kindNames = [kindCount]string{
|
|
"void", "bool", "int", "float", "string", "Vec2", "Vec3", "Color", "Quat", "Rect",
|
|
"Transform2D", "Transform3D", "NodeRef", "AssetRef", "ComponentRef", "enum", "struct", "slice",
|
|
"Coroutine", "Connection", "ScriptRef",
|
|
}
|
|
|
|
func (k Kind) String() string {
|
|
if k < kindCount {
|
|
return kindNames[k]
|
|
}
|
|
return "kind" + strconv.Itoa(int(k))
|
|
}
|
|
|
|
type TypeRef struct {
|
|
Kind Kind
|
|
Name string
|
|
Elem *TypeRef
|
|
}
|
|
|
|
func T(k Kind) TypeRef {
|
|
return TypeRef{Kind: k}
|
|
}
|
|
|
|
func SliceOf(e TypeRef) TypeRef {
|
|
return TypeRef{Kind: Slice, Elem: &e}
|
|
}
|
|
|
|
func AssetOf(kind string) TypeRef {
|
|
return TypeRef{Kind: AssetRef, Name: kind}
|
|
}
|
|
|
|
func ComponentOf(name string) TypeRef {
|
|
return TypeRef{Kind: ComponentRef, Name: name}
|
|
}
|
|
|
|
func EnumOf(qualified string) TypeRef {
|
|
return TypeRef{Kind: Enum, Name: qualified}
|
|
}
|
|
|
|
func StructOf(qualified string) TypeRef {
|
|
return TypeRef{Kind: Struct, Name: qualified}
|
|
}
|
|
|
|
func ScriptRefOf(script string) TypeRef {
|
|
return TypeRef{Kind: ScriptRef, Name: script}
|
|
}
|
|
|
|
func (t TypeRef) String() string {
|
|
switch t.Kind {
|
|
case Slice:
|
|
if t.Elem == nil {
|
|
return "[]void"
|
|
}
|
|
return "[]" + t.Elem.String()
|
|
case AssetRef:
|
|
return "AssetRef<" + t.Name + ">"
|
|
case ComponentRef:
|
|
return "ComponentRef<" + t.Name + ">"
|
|
case ScriptRef:
|
|
return "ScriptRef<" + t.Name + ">"
|
|
case Enum:
|
|
return "enum:" + t.Name
|
|
case Struct:
|
|
return "struct:" + t.Name
|
|
}
|
|
return t.Kind.String()
|
|
}
|
|
|
|
func Parse(s string) (TypeRef, bool) {
|
|
switch {
|
|
case strings.HasPrefix(s, "[]"):
|
|
e, ok := Parse(s[2:])
|
|
if !ok || e.Kind == Void {
|
|
return TypeRef{}, false
|
|
}
|
|
return SliceOf(e), true
|
|
case strings.HasPrefix(s, "AssetRef<") && strings.HasSuffix(s, ">"):
|
|
return AssetOf(s[len("AssetRef<") : len(s)-1]), true
|
|
case strings.HasPrefix(s, "ComponentRef<") && strings.HasSuffix(s, ">"):
|
|
return ComponentOf(s[len("ComponentRef<") : len(s)-1]), true
|
|
case strings.HasPrefix(s, "ScriptRef<") && strings.HasSuffix(s, ">"):
|
|
return ScriptRefOf(s[len("ScriptRef<") : len(s)-1]), len(s) > len("ScriptRef<>")
|
|
case strings.HasPrefix(s, "enum:"):
|
|
return EnumOf(s[5:]), len(s) > 5
|
|
case strings.HasPrefix(s, "struct:"):
|
|
return StructOf(s[7:]), len(s) > 7
|
|
case s == "Coroutine":
|
|
return T(Coroutine), true
|
|
case s == "Connection":
|
|
return T(Connection), true
|
|
}
|
|
for k := Void; k < Enum; k++ {
|
|
if kindNames[k] == s && k != AssetRef && k != ComponentRef {
|
|
return T(k), true
|
|
}
|
|
}
|
|
return TypeRef{}, false
|
|
}
|
|
|
|
func (t TypeRef) Equal(o TypeRef) bool {
|
|
if t.Kind != o.Kind || t.Name != o.Name {
|
|
return false
|
|
}
|
|
if t.Kind == Slice {
|
|
if t.Elem == nil || o.Elem == nil {
|
|
return t.Elem == o.Elem
|
|
}
|
|
return t.Elem.Equal(*o.Elem)
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (t TypeRef) Slots() int {
|
|
switch t.Kind {
|
|
case Void:
|
|
return 0
|
|
case Transform2D, Transform3D:
|
|
return 3
|
|
}
|
|
return 1
|
|
}
|
|
|
|
func (t TypeRef) Heap() bool {
|
|
return t.Kind == String || t.Kind == Slice
|
|
}
|
|
|
|
type Signature struct {
|
|
Params []TypeRef
|
|
Result TypeRef
|
|
}
|
|
|
|
func Sig(result TypeRef, params ...TypeRef) Signature {
|
|
return Signature{Params: params, Result: result}
|
|
}
|
|
|
|
func (s Signature) String() string {
|
|
var b strings.Builder
|
|
b.WriteByte('(')
|
|
for i, p := range s.Params {
|
|
if i > 0 {
|
|
b.WriteString(", ")
|
|
}
|
|
b.WriteString(p.String())
|
|
}
|
|
b.WriteByte(')')
|
|
if s.Result.Kind != Void {
|
|
b.WriteByte(' ')
|
|
b.WriteString(s.Result.String())
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func (s Signature) ParamSlots() int {
|
|
n := 0
|
|
for _, p := range s.Params {
|
|
n += p.Slots()
|
|
}
|
|
return n
|
|
}
|
|
|
|
func (s Signature) ResultSlots() int {
|
|
return s.Result.Slots()
|
|
}
|
|
|
|
func (s Signature) Window() int {
|
|
return max(s.ParamSlots(), s.ResultSlots())
|
|
}
|
|
|
|
func (s Signature) Equal(o Signature) bool {
|
|
if len(s.Params) != len(o.Params) || !s.Result.Equal(o.Result) {
|
|
return false
|
|
}
|
|
for i := range s.Params {
|
|
if !s.Params[i].Equal(o.Params[i]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (s Signature) Validate() error {
|
|
for i, p := range s.Params {
|
|
if !hostable(p, true) {
|
|
return fmt.Errorf("param %d: %s cannot cross the host boundary", i, p)
|
|
}
|
|
}
|
|
if s.Result.Kind != Void && !hostable(s.Result, false) {
|
|
return fmt.Errorf("result: %s cannot cross the host boundary", s.Result)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func hostable(t TypeRef, param bool) bool {
|
|
switch t.Kind {
|
|
case Void, Coroutine, Connection, ScriptRef:
|
|
return false
|
|
case Slice:
|
|
return param && t.Elem != nil && Plain(*t.Elem)
|
|
}
|
|
return true
|
|
}
|
|
|
|
func Plain(t TypeRef) bool {
|
|
switch t.Kind {
|
|
case Void, String, Slice, Coroutine, Connection, ScriptRef:
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
type EnumMember struct {
|
|
Name string
|
|
Value int64
|
|
}
|
|
|
|
type EnumDef struct {
|
|
Module string
|
|
Name string
|
|
Members []EnumMember
|
|
}
|
|
|
|
func (e *EnumDef) Qualified() string {
|
|
return e.Module + "." + e.Name
|
|
}
|
|
|
|
type StructField struct {
|
|
Name string
|
|
Type TypeRef
|
|
}
|
|
|
|
type StructDef struct {
|
|
Module string
|
|
Name string
|
|
Fields []StructField
|
|
Slots int
|
|
}
|
|
|
|
func (s *StructDef) Qualified() string {
|
|
return s.Module + "." + s.Name
|
|
}
|
|
|
|
type EventDef struct {
|
|
Name string
|
|
Params []TypeRef
|
|
}
|
|
|
|
func (e EventDef) Sig() Signature {
|
|
return Signature{Params: e.Params, Result: T(Void)}
|
|
}
|
|
|
|
type Const struct {
|
|
Type TypeRef
|
|
Int int64
|
|
Float float64
|
|
Bool bool
|
|
Str string
|
|
}
|
|
|
|
type Field struct {
|
|
Name string
|
|
Type TypeRef
|
|
ReadOnly bool
|
|
Index int
|
|
}
|
|
|
|
type Component struct {
|
|
Name string
|
|
Short string
|
|
Index int
|
|
Fields []Field
|
|
}
|
|
|
|
func (c *Component) Field(name string) (*Field, bool) {
|
|
for i := range c.Fields {
|
|
if c.Fields[i].Name == name {
|
|
return &c.Fields[i], true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
type Surface interface {
|
|
Module(path string) bool
|
|
Func(module, name string) (Signature, bool)
|
|
Method(recv Kind, name string) (Signature, bool)
|
|
ComponentMethod(comp, name string) (Signature, bool)
|
|
Const(module, name string) (Const, bool)
|
|
Enum(module, name string) (*EnumDef, bool)
|
|
Struct(module, name string) (*StructDef, bool)
|
|
Event(name string) (Signature, bool)
|
|
Components(name string) []*Component
|
|
Slots(t TypeRef) int
|
|
Hash() [32]byte
|
|
}
|
|
|
|
func Exported(name string) bool {
|
|
r, _ := utf8.DecodeRuneInString(name)
|
|
return unicode.IsUpper(r)
|
|
}
|