fspl/entity/type.go

279 lines
7.3 KiB
Go

package entity
import "fmt"
import "github.com/google/uuid"
import "git.tebibyte.media/fspl/fspl/errors"
// Type is any type notation.
type Type interface {
fmt.Stringer
// Equals reports whether this type is equivalent to another type.
Equals (ty Type) bool
// Access reports the access permission of the type.
Access () Access
// Unit reports the unit that the type was defined in.
Unit () uuid.UUID
ty ()
}
// TypeNamed refers to a user-defined or built in named type.
type TypeNamed struct {
// Syntax
Position errors.Position
UnitNickname string
Name string
Type Type
// Semantics
Acc Access
Unt uuid.UUID
}
func (*TypeNamed) ty(){}
func (this *TypeNamed) Access () Access { return this.Acc }
func (this *TypeNamed) Unit () uuid.UUID { return this.Unt }
func (this *TypeNamed) String () string {
if this.UnitNickname == "" {
return this.Name
} else {
return fmt.Sprint(this.UnitNickname, "::", this.Name)
}
}
func (this *TypeNamed) Equals (ty Type) bool {
real, ok := ty.(*TypeNamed)
return ok && TypesEqual(real.Type, this.Type)
}
// TypePointer is a pointer to another type.
type TypePointer struct {
Position errors.Position
Referenced Type
// Semantics
Acc Access
Unt uuid.UUID
}
func (*TypePointer) ty(){}
func (this *TypePointer) Access () Access { return this.Acc }
func (this *TypePointer) Unit () uuid.UUID { return this.Unt }
func (this *TypePointer) String () string {
return fmt.Sprint("*", this.Referenced)
}
func (this *TypePointer) Equals (ty Type) bool {
real, ok := ty.(*TypePointer)
return ok && TypesEqual(real.Referenced, this.Referenced)
}
// 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 {
Position errors.Position
Element Type
// Semantics
Acc Access
Unt uuid.UUID
}
func (*TypeSlice) ty(){}
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) Equals (ty Type) bool {
real, ok := ty.(*TypeSlice)
return ok && TypesEqual(real.Element, this.Element)
}
// 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 {
Position errors.Position
Length int
Element Type
// Semantics
Acc Access
Unt uuid.UUID
}
func (*TypeArray) ty(){}
func (this *TypeArray) Access () Access { return this.Acc }
func (this *TypeArray) Unit () uuid.UUID { return this.Unt }
func (this *TypeArray) String () string {
return fmt.Sprint(this.Length, ":", this.Element)
}
func (this *TypeArray) Equals (ty Type) bool {
real, ok := ty.(*TypeArray)
return ok &&
real.Length == this.Length &&
TypesEqual(real.Element, this.Element)
}
// TypeStruct is a composite type that stores keyed values. The positions of the
// 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
Position errors.Position
Members []*Declaration
// Semantics
Acc Access
Unt uuid.UUID
MemberOrder []string
MemberMap map[string] *Declaration
}
func (*TypeStruct) ty(){}
func (this *TypeStruct) Access () Access { return this.Acc }
func (this *TypeStruct) Unit () uuid.UUID { return this.Unt }
func (this *TypeStruct) String () string {
out := "(."
for _, member := range this.Members {
out += fmt.Sprint(" ", member)
}
return out + ")"
}
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 {
if !TypesEqual(member.Type(), real.Members[index].Type()) {
return false
}
}
return true
}
// 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.
type TypeInterface struct {
// Syntax
Position errors.Position
Behaviors []*Signature
// Semantics
Acc Access
Unt uuid.UUID
BehaviorOrder []string
BehaviorMap map[string] *Signature
}
func (*TypeInterface) ty(){}
func (this *TypeInterface) Access () Access { return this.Acc }
func (this *TypeInterface) Unit () uuid.UUID { return this.Unt }
func (this *TypeInterface) String () string {
out := "(~"
for _, behavior := range this.Behaviors {
out += fmt.Sprint(" ", behavior)
}
return out + ")"
}
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
}
// TypeInt represents any signed or unsigned integer type.
type TypeInt struct {
Position errors.Position
Width int
Signed bool
// Semantics
Acc Access
Unt uuid.UUID
}
func (*TypeInt) ty(){}
func (this *TypeInt) Access () Access { return this.Acc }
func (this *TypeInt) Unit () uuid.UUID { return this.Unt }
func (this *TypeInt) String () string {
if this.Signed {
return fmt.Sprint("I", this.Width)
} else {
return fmt.Sprint("U", this.Width)
}
}
func (this *TypeInt) Equals (ty Type) bool {
real, ok := ty.(*TypeInt)
return ok && real.Width == this.Width && real.Signed == this.Signed
}
// TypeFloat represents any floating point type.
type TypeFloat struct {
Position errors.Position
Width int
// Semantics
Acc Access
Unt uuid.UUID
}
func (*TypeFloat) ty(){}
func (this *TypeFloat) Access () Access { return this.Acc }
func (this *TypeFloat) Unit () uuid.UUID { return this.Unt }
func (this *TypeFloat) String () string {
return fmt.Sprint("F", this.Width)
}
func (this *TypeFloat) Equals (ty Type) bool {
real, ok := ty.(*TypeFloat)
return ok && real.Width == this.Width
}
// 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 {
Position errors.Position
Signed bool
// Semantics
Acc Access
Unt uuid.UUID
}
func (*TypeWord) ty(){}
func (this *TypeWord) Access () Access { return this.Acc }
func (this *TypeWord) Unit () uuid.UUID { return this.Unt }
func (this *TypeWord) String () string {
if this.Signed {
return "Int"
} else {
return "UInt"
}
}
func (this *TypeWord) Equals (ty Type) bool {
real, ok := ty.(*TypeWord)
return ok && real.Signed == this.Signed
}
// 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)
}
// 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()
}
}