fspl/entity/type.go

404 lines
11 KiB
Go
Raw Permalink Normal View History

package entity
2023-09-18 04:13:55 +00:00
import "fmt"
import "strings"
2024-02-14 06:48:47 +00:00
import "github.com/google/uuid"
2024-02-23 00:22:53 +00:00
import "git.tebibyte.media/fspl/fspl/errors"
2023-09-18 04:13:55 +00:00
// Type is any type notation.
type Type interface {
fmt.Stringer
2024-03-02 06:26:29 +00:00
// Position returns the position of the type within its source file.
Position () errors.Position
// Equals returns whether this type is equivalent to another type.
2023-10-20 01:53:19 +00:00
Equals (ty Type) bool
// Access returns the access control mode of the type.
Access () Access
// Unit returns the unit that the type was defined in.
Unit () uuid.UUID
// Hash returns a hash of this type that fits within a uint64.
Hash () Hash
2023-09-18 04:13:55 +00:00
ty ()
}
// TypeNamed refers to a user-defined or built in named type.
type TypeNamed struct {
2024-02-14 15:22:33 +00:00
// Syntax
2024-03-02 06:26:29 +00:00
Pos errors.Position
UnitNickname string
Name string
Type Type
2024-02-14 15:22:33 +00:00
// Semantics
Acc Access
Unt uuid.UUID
2023-09-18 04:13:55 +00:00
}
func (*TypeNamed) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypeNamed) Position () errors.Position { return this.Pos }
func (this *TypeNamed) Access () Access { return this.Acc }
func (this *TypeNamed) Unit () uuid.UUID { return this.Unt }
2023-12-19 20:21:10 +00:00
func (this *TypeNamed) String () string {
if this.UnitNickname == "" {
2023-12-19 20:21:10 +00:00
return this.Name
} else {
return fmt.Sprint(this.UnitNickname, "::", this.Name)
2023-12-19 20:21:10 +00:00
}
}
func (this *TypeNamed) Hash () Hash {
return Key {
Unit: this.Type.Unit(),
Name: this.Name,
}.Hash()
}
2023-10-20 01:53:19 +00:00
func (this *TypeNamed) Equals (ty Type) bool {
real, ok := ty.(*TypeNamed)
return ok && TypesEqual(real.Type, this.Type)
2023-10-20 01:53:19 +00:00
}
2023-09-18 04:13:55 +00:00
// TypePointer is a pointer to another type.
type TypePointer struct {
2024-03-02 06:26:29 +00:00
Pos errors.Position
2024-02-05 20:17:59 +00:00
Referenced Type
// Semantics
Acc Access
Unt uuid.UUID
2023-09-18 04:13:55 +00:00
}
func (*TypePointer) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypePointer) Position () errors.Position { return this.Pos }
func (this *TypePointer) Access () Access { return this.Acc }
func (this *TypePointer) Unit () uuid.UUID { return this.Unt }
2023-09-18 04:13:55 +00:00
func (this *TypePointer) String () string {
return fmt.Sprint("*", this.Referenced)
}
func (this *TypePointer) Hash () Hash {
referenced := HashType(this.Referenced)
return NewHash(append([]byte("TypePointer:"), referenced[:]...))
}
2023-10-20 01:53:19 +00:00
func (this *TypePointer) Equals (ty Type) bool {
real, ok := ty.(*TypePointer)
2023-11-01 01:52:47 +00:00
return ok && TypesEqual(real.Referenced, this.Referenced)
2023-10-20 01:53:19 +00:00
}
2023-09-18 04:13:55 +00:00
// TypeSlice is a pointer to several values of a given type stored next to
// eachother. Its length is not built into its type and can be changed at
// runtime.
type TypeSlice struct {
2024-03-02 06:26:29 +00:00
Pos errors.Position
2024-02-05 20:17:59 +00:00
Element Type
// Semantics
Acc Access
Unt uuid.UUID
}
func (*TypeSlice) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypeSlice) Position () errors.Position { return this.Pos }
func (this *TypeSlice) Access () Access { return this.Acc }
func (this *TypeSlice) Unit () uuid.UUID { return this.Unt }
func (this *TypeSlice) String () string {
return fmt.Sprint("*:", this.Element)
}
func (this *TypeSlice) Hash () Hash {
referenced := HashType(this.Element)
return NewHash(append([]byte("TypeSlice:"), referenced[:]...))
}
2023-10-20 01:53:19 +00:00
func (this *TypeSlice) Equals (ty Type) bool {
real, ok := ty.(*TypeSlice)
2023-11-01 01:52:47 +00:00
return ok && TypesEqual(real.Element, this.Element)
2023-10-20 01:53:19 +00:00
}
2023-09-18 04:13:55 +00:00
// TypeArray is a group of values of a given type stored next to eachother. The
// length of an array is fixed and is part of its type. Arrays are passed by
// value unless a pointer is used.
type TypeArray struct {
2024-03-02 06:26:29 +00:00
Pos errors.Position
2024-02-05 20:17:59 +00:00
Length int
Element Type
// Semantics
Acc Access
Unt uuid.UUID
2023-09-18 04:13:55 +00:00
}
func (*TypeArray) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypeArray) Position () errors.Position { return this.Pos }
func (this *TypeArray) Access () Access { return this.Acc }
func (this *TypeArray) Unit () uuid.UUID { return this.Unt }
2023-09-18 04:13:55 +00:00
func (this *TypeArray) String () string {
2023-09-18 06:12:27 +00:00
return fmt.Sprint(this.Length, ":", this.Element)
2023-09-18 04:13:55 +00:00
}
func (this *TypeArray) Hash () Hash {
referenced := HashType(this.Element)
return NewHash(append (
2024-03-02 06:26:29 +00:00
[]byte(fmt.Sprintf("TypeArray:%d:", this.Length)),
referenced[:]...))
}
2023-10-20 01:53:19 +00:00
func (this *TypeArray) Equals (ty Type) bool {
real, ok := ty.(*TypeArray)
return ok &&
real.Length == this.Length &&
2023-11-01 01:52:47 +00:00
TypesEqual(real.Element, this.Element)
2023-10-20 01:53:19 +00:00
}
2023-09-18 04:13:55 +00:00
2023-10-07 05:18:05 +00:00
// TypeStruct is a composite type that stores keyed values. The positions of the
2023-09-18 04:13:55 +00:00
// values within the struct are decided at compile time, based on the order they
// are specified in. Structs are passed by value unless a pointer is used.
type TypeStruct struct {
// Syntax
2024-03-02 06:26:29 +00:00
Pos errors.Position
2024-02-05 20:17:59 +00:00
Members []*Declaration
// Semantics
Acc Access
Unt uuid.UUID
MemberOrder []string
MemberMap map[string] *Declaration
2023-09-18 04:13:55 +00:00
}
func (*TypeStruct) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypeStruct) Position () errors.Position { return this.Pos }
func (this *TypeStruct) Access () Access { return this.Acc }
func (this *TypeStruct) Unit () uuid.UUID { return this.Unt }
2023-09-18 04:13:55 +00:00
func (this *TypeStruct) String () string {
out := "(."
for _, member := range this.Members {
out += fmt.Sprint(" ", member)
2023-09-18 04:13:55 +00:00
}
return out + ")"
}
func (this *TypeStruct) Hash () Hash {
data := new(strings.Builder)
data.WriteString("TypeStruct:")
for _, member := range this.Members {
memberHash := HashType(member.Type())
data.Write(memberHash[:])
}
return NewHash([]byte(data.String()))
}
2023-10-20 01:53:19 +00:00
func (this *TypeStruct) Equals (ty Type) bool {
real, ok := ty.(*TypeStruct)
if !ok || len(real.Members) != len(this.Members) { return false }
for index, member := range this.Members {
2023-11-01 01:52:47 +00:00
if !TypesEqual(member.Type(), real.Members[index].Type()) {
2023-10-20 01:53:19 +00:00
return false
}
}
return true
}
2023-09-18 04:13:55 +00:00
2023-10-07 05:18:05 +00:00
// TypeInterface is a polymorphic pointer that allows any value of any type
// through, except it must have at least the methods defined within the
// interface. Interfaces are always passed by reference. When assigning a value
// to an interface, it will be referenced automatically. When assigning a
// pointer to an interface, the pointer's reference will be used instead.
2023-09-18 04:13:55 +00:00
type TypeInterface struct {
// Syntax
2024-03-02 06:26:29 +00:00
Pos errors.Position
2024-02-05 20:17:59 +00:00
Behaviors []*Signature
// Semantics
Acc Access
Unt uuid.UUID
BehaviorOrder []string
BehaviorMap map[string] *Signature
2023-09-18 04:13:55 +00:00
}
func (*TypeInterface) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypeInterface) Position () errors.Position { return this.Pos }
func (this *TypeInterface) Access () Access { return this.Acc }
func (this *TypeInterface) Unit () uuid.UUID { return this.Unt }
2023-09-18 04:13:55 +00:00
func (this *TypeInterface) String () string {
2024-03-14 03:05:58 +00:00
out := "(&"
for _, behavior := range this.Behaviors {
out += fmt.Sprint(" ", behavior)
2023-09-18 04:13:55 +00:00
}
return out + ")"
}
func (this *TypeInterface) Hash () Hash {
data := new(strings.Builder)
data.WriteString("TypeInterface:")
for _, behavior := range this.Behaviors {
behaviorHash := HashType(behavior)
data.Write(behaviorHash[:])
}
return NewHash([]byte(data.String()))
}
2023-10-20 01:53:19 +00:00
func (this *TypeInterface) Equals (ty Type) bool {
real, ok := ty.(*TypeInterface)
if !ok || len(real.Behaviors) != len(this.Behaviors) { return false }
for index, behavior := range this.Behaviors {
if !behavior.Equals(real.Behaviors[index]) {
return false
}
}
return true
}
2023-10-07 05:18:05 +00:00
2024-03-01 08:00:17 +00:00
// TypeUnion is a polymorphic type that can hold any value as long as it is one
// of a list of allowed types. It is not a pointer. It holds the hash of the
// actual type of the value stored within it, followed by the value. The hash
// field is computed using the type's name, and the UUID that it was defined in.
// If it is not named, then the hash is computed using the structure of the
// type. The value field is always big enough to hold the largest type in the
// allowed list.
type TypeUnion struct {
// Syntax
2024-03-02 06:26:29 +00:00
Pos errors.Position
2024-03-01 08:00:17 +00:00
Allowed []Type
// Semantics
Acc Access
Unt uuid.UUID
AllowedOrder []Hash
AllowedMap map[Hash] Type
2024-03-01 08:00:17 +00:00
}
func (*TypeUnion) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypeUnion) Position () errors.Position { return this.Pos }
2024-03-01 08:00:17 +00:00
func (this *TypeUnion) Access () Access { return this.Acc }
func (this *TypeUnion) Unit () uuid.UUID { return this.Unt }
func (this *TypeUnion) String () string {
out := "(|"
for _, ty := range this.Allowed {
out += fmt.Sprint(" ", ty)
}
return out + ")"
}
func (this *TypeUnion) Hash () Hash {
data := new(strings.Builder)
data.WriteString("TypeUnion:")
for _, ty := range this.Allowed {
typeHash := HashType(ty)
data.Write(typeHash[:])
}
return NewHash([]byte(data.String()))
}
func (this *TypeUnion) Equals (ty Type) bool {
real, ok := ty.(*TypeUnion)
if !ok || len(real.Allowed) != len(this.Allowed) { return false }
for index, ty := range this.Allowed {
if !ty.Equals(real.Allowed[index]) {
return false
}
}
return true
}
2023-10-07 05:18:05 +00:00
// TypeInt represents any signed or unsigned integer type.
type TypeInt struct {
2024-03-02 06:26:29 +00:00
Pos errors.Position
2024-02-05 20:16:11 +00:00
Width int
Signed bool
// Semantics
Acc Access
Unt uuid.UUID
2023-10-07 05:18:05 +00:00
}
func (*TypeInt) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypeInt) Position () errors.Position { return this.Pos }
func (this *TypeInt) Access () Access { return this.Acc }
func (this *TypeInt) Unit () uuid.UUID { return this.Unt }
2023-10-20 01:53:19 +00:00
func (this *TypeInt) String () string {
if this.Signed {
return fmt.Sprint("I", this.Width)
} else {
return fmt.Sprint("U", this.Width)
}
2023-10-20 01:53:19 +00:00
}
func (this *TypeInt) Hash () Hash {
return NewHash([]byte(fmt.Sprintf (
"TypeInt:%d:%t",
this.Width, this.Signed)))
}
2023-10-20 01:53:19 +00:00
func (this *TypeInt) Equals (ty Type) bool {
real, ok := ty.(*TypeInt)
return ok && real.Width == this.Width && real.Signed == this.Signed
}
2023-10-07 05:18:05 +00:00
// TypeFloat represents any floating point type.
type TypeFloat struct {
2024-03-02 06:26:29 +00:00
Pos errors.Position
2024-02-05 20:16:11 +00:00
Width int
// Semantics
Acc Access
Unt uuid.UUID
2023-10-07 05:18:05 +00:00
}
func (*TypeFloat) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypeFloat) Position () errors.Position { return this.Pos }
func (this *TypeFloat) Access () Access { return this.Acc }
func (this *TypeFloat) Unit () uuid.UUID { return this.Unt }
2023-10-20 01:53:19 +00:00
func (this *TypeFloat) String () string {
return fmt.Sprint("F", this.Width)
}
func (this *TypeFloat) Hash () Hash {
return NewHash([]byte(fmt.Sprintf("TypeFloat:%d", this.Width)))
}
2023-10-20 01:53:19 +00:00
func (this *TypeFloat) Equals (ty Type) bool {
real, ok := ty.(*TypeFloat)
return ok && real.Width == this.Width
}
2023-10-07 05:18:05 +00:00
// TypeWord represents an integer type of unspecified width. The optimal width
// is chosen based on the machine word size (32 on 32 bit systems, 64 on 64 bit
// systems, etc)
type TypeWord struct {
2024-03-02 06:26:29 +00:00
Pos errors.Position
2024-02-05 20:16:11 +00:00
Signed bool
// Semantics
Acc Access
Unt uuid.UUID
2023-10-07 05:18:05 +00:00
}
func (*TypeWord) ty(){}
2024-03-02 06:26:29 +00:00
func (this *TypeWord) Position () errors.Position { return this.Pos }
func (this *TypeWord) Access () Access { return this.Acc }
func (this *TypeWord) Unit () uuid.UUID { return this.Unt }
2023-10-20 01:53:19 +00:00
func (this *TypeWord) String () string {
if this.Signed {
return "Int"
} else {
return "UInt"
}
}
func (this *TypeWord) Hash () Hash {
return NewHash([]byte(fmt.Sprintf("TypeWord:%t", this.Signed)))
}
2023-10-20 01:53:19 +00:00
func (this *TypeWord) Equals (ty Type) bool {
real, ok := ty.(*TypeWord)
return ok && real.Signed == this.Signed
}
2023-10-26 14:43:50 +00:00
2023-11-01 01:52:47 +00:00
// TypesEqual checks if two types are equal to eachother, even if one or both
// are nil.
func TypesEqual (left, right Type) bool {
if (left == nil) != (right == nil) { return false }
if left == nil { return true }
return left.Equals(right)
}
2024-02-12 19:34:49 +00:00
// FormatType returns a string representing a type. If the type is nil, it
// returns "Void".
func FormatType (ty Type) string {
if ty == nil {
return "Void"
} else {
return ty.String()
}
}
// HashType returns a hash representing a type. If the type is nil, it returns
// NewHash([]byte("TypeVoid"))
func HashType (ty Type) Hash {
if ty == nil {
return NewHash([]byte("TypeVoid"))
} else {
return ty.Hash()
}
}