213 lines
5.6 KiB
Go
213 lines
5.6 KiB
Go
package entity
|
|
|
|
import "fmt"
|
|
import "github.com/alecthomas/participle/v2/lexer"
|
|
|
|
// Type is any type notation.
|
|
type Type interface {
|
|
fmt.Stringer
|
|
|
|
// Equals reports whether this type is equivalent to another type.
|
|
Equals (ty Type) bool
|
|
|
|
ty ()
|
|
}
|
|
|
|
// TypeNamed refers to a user-defined or built in named type.
|
|
type TypeNamed struct {
|
|
Pos lexer.Position
|
|
Module string `parser:" (@Ident '::')? "`
|
|
Name string `parser:" @TypeIdent "`
|
|
Type Type
|
|
}
|
|
func (*TypeNamed) ty(){}
|
|
func (this *TypeNamed) String () string {
|
|
if this.Module == "" {
|
|
return this.Name
|
|
} else {
|
|
return fmt.Sprint(this.Module, "::", this.Name)
|
|
}
|
|
}
|
|
func (this *TypeNamed) Equals (ty Type) bool {
|
|
real, ok := ty.(*TypeNamed)
|
|
return ok && real.Name == this.Name && real.Module == this.Module
|
|
}
|
|
|
|
// TypePointer is a pointer to another type.
|
|
type TypePointer struct {
|
|
Pos lexer.Position
|
|
Referenced Type `parser:" '*' @@ "`
|
|
}
|
|
func (*TypePointer) ty(){}
|
|
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 {
|
|
Pos lexer.Position
|
|
Element Type `parser:" '*' ':' @@ "`
|
|
}
|
|
func (*TypeSlice) ty(){}
|
|
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 {
|
|
Pos lexer.Position
|
|
Length int `parser:" @Int "`
|
|
Element Type `parser:" ':' @@ "`
|
|
}
|
|
func (*TypeArray) ty(){}
|
|
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
|
|
Pos lexer.Position
|
|
Members []*Declaration `parser:" '(' @@+ ')' "`
|
|
|
|
// Semantics
|
|
MemberOrder []string
|
|
MemberMap map[string] *Declaration
|
|
}
|
|
func (*TypeStruct) ty(){}
|
|
func (this *TypeStruct) String () string {
|
|
out := "("
|
|
for index, member := range this.Members {
|
|
if index > 0 { out += " " }
|
|
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
|
|
Pos lexer.Position
|
|
Behaviors []*Signature `parser:" '(' @@+ ')' "`
|
|
|
|
// Semantics
|
|
BehaviorOrder []string
|
|
BehaviorMap map[string] *Signature
|
|
}
|
|
func (*TypeInterface) ty(){}
|
|
func (this *TypeInterface) String () string {
|
|
out := "("
|
|
for index, behavior := range this.Behaviors {
|
|
if index > 0 { out += " " }
|
|
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 {
|
|
Pos lexer.Position
|
|
Width int
|
|
Signed bool
|
|
}
|
|
func (*TypeInt) ty(){}
|
|
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 {
|
|
Pos lexer.Position
|
|
Width int
|
|
}
|
|
func (*TypeFloat) ty(){}
|
|
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 {
|
|
Pos lexer.Position
|
|
Signed bool
|
|
}
|
|
func (*TypeWord) ty(){}
|
|
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)
|
|
}
|