package entity import "fmt" import "encoding/base64" import "github.com/google/uuid" import "git.tebibyte.media/fspl/fspl/errors" // Key globally indexes top level entities in contexts where modules matter. type Key struct { Unit uuid.UUID Name string Method string } func (key Key) String () string { out := fmt.Sprintf("%v::%v", key.Unit, key.Name) if key.Method != "" { out = fmt.Sprintf("%s.%s", out, key.Method) } return out } // LinkName returns the name that the entity it refers to will be given when // compiled. func (key Key) LinkName () string { data := [16]byte(key.Unit) out := fmt.Sprintf( "%s::%s", base64.StdEncoding.EncodeToString(data[:]), key.Name) if key.Method != "" { out = fmt.Sprintf("%s.%s", out, key.Method) } return out } // StripMethod returns a copy of the key that refers to a type instead of a // method. func (key Key) StripMethod () Key { key.Method = "" return key } // TopLevel is any construct that is placed at the root of a file. type TopLevel interface { topLevel () } // Access determines the external access control mode for a top-level entity. type Access int; const ( // AccessPublic allows other modules to access an entity normally. AccessPublic Access = iota // AccessRestricted causes a top-level entity to appear opaque to other // modules. Values of restricted types can be passed around, assigned // to eachother, and their methods can be called, but the implementation // of the type is entirely hidden. This access mode cannot be applied to // functions. AccessRestricted // AccessPrivate disallows other modules from accessing a top-level // entity. AccessPrivate ) func (this Access) String () string { switch this { case AccessPrivate: return "-" case AccessRestricted: return "~" case AccessPublic: return "+" default: return fmt.Sprintf("entity.Access(%d)", this) } } // Typedef binds a type to a global identifier. type Typedef struct { // Syntax Position errors.Position Acc Access Name string Type Type // Semantics Unit uuid.UUID Methods map[string] *Method } func (*Typedef) topLevel(){} func (this *Typedef) String () string { output := "" output += fmt.Sprint(this.Acc, " ") output += fmt.Sprint(this.Name, ": ", this.Type) if this.Methods != nil { for _, method := range this.Methods { output += fmt.Sprint("\n", method) } } return output } // Function binds a global identifier and argument list to an expression which // is evaluated each time the function is called. If no expression is specified, // the function is marked as external. Functions have an argument list, where // each argument is passed as a separate variable. They return one value. All of // these are typed. type Function struct { // Syntax Position errors.Position Acc Access LinkName string Signature *Signature Body Expression // Semantics Unit uuid.UUID Scope } func (*Function) topLevel(){} func (this *Function) String () string { output := "" output += fmt.Sprint(this.Acc, " ") output += this.Signature.String() if this.LinkName != "" { output += fmt.Sprint(" '", this.LinkName, "'") } if this.Body != nil { output += fmt.Sprint(" = ", this.Body) } return output } // Method is like a function, except localized to a defined type. Methods are // called on an instance of that type, and receive a pointer to that instance // via the "this" variable when they are run. Method names are not globally // unique, but are unique within the type they are defined on. type Method struct { // Syntax Position errors.Position Acc Access TypeName string LinkName string Signature *Signature Body Expression // Semantics Unit uuid.UUID Type Type This *Declaration Scope } func (*Method) topLevel(){} func (this *Method) String () string { output := "" output += fmt.Sprint(this.Acc, " ") output += fmt.Sprint(this.TypeName, ".", this.Signature) if this.LinkName != "" { output += fmt.Sprint(" '", this.LinkName, "'") } if this.Body != nil { output += fmt.Sprint(" = ", this.Body) } return output }