Implemented parser
This commit is contained in:
5
go.mod
Normal file
5
go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module git.tebibyte.media/sashakoshka/fspl
|
||||
|
||||
go 1.21.0
|
||||
|
||||
require github.com/alecthomas/participle/v2 v2.1.0
|
||||
8
go.sum
Normal file
8
go.sum
Normal file
@@ -0,0 +1,8 @@
|
||||
github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0=
|
||||
github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
|
||||
github.com/alecthomas/participle/v2 v2.1.0 h1:z7dElHRrOEEq45F2TG5cbQihMtNTv8vwldytDj7Wrz4=
|
||||
github.com/alecthomas/participle/v2 v2.1.0/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c=
|
||||
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
|
||||
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
270
parser/expression.go
Normal file
270
parser/expression.go
Normal file
@@ -0,0 +1,270 @@
|
||||
package parser
|
||||
|
||||
import "fmt"
|
||||
import "github.com/alecthomas/participle/v2/lexer"
|
||||
|
||||
type Expression interface {
|
||||
expression ()
|
||||
}
|
||||
|
||||
// Variable specifies a named variable. It can be assigned to a type matching
|
||||
// the variable declaration's type. Since it contains inherent type information,
|
||||
// it may be directly assigned to an interface. A variable is always a valid
|
||||
// location expression.
|
||||
type Variable struct {
|
||||
Pos lexer.Position
|
||||
Name string `parser:" @Ident "`
|
||||
}
|
||||
func (*Variable) expression(){}
|
||||
func (this *Variable) String () string {
|
||||
return this.Name
|
||||
}
|
||||
|
||||
// Declaration binds a local identifier to a typed variable, but also acts as a
|
||||
// variable expression allowing the variable to be used the moment it is
|
||||
// defined. Since it contains inherent type information, it may be directly
|
||||
// assigned to an interface. A declaration is always a valid location
|
||||
// expression.
|
||||
type Declaration struct {
|
||||
Pos lexer.Position
|
||||
Name string `parser:" @Ident "`
|
||||
Type Type `parser:" ':' @@ "`
|
||||
}
|
||||
func (*Declaration) expression(){}
|
||||
func (this *Declaration) String () string {
|
||||
return fmt.Sprint(this.Name, ":", this.Type)
|
||||
}
|
||||
|
||||
// Call calls upon the function specified by the first argument, and passes the
|
||||
// rest of that argument to the function. The first argument must be a function
|
||||
// type, usually the name of a function. The result of a call may be assigned to
|
||||
// any type matching the function's return type. Since it contains inherent type
|
||||
// information, it may be directly assigned to an interface. A call is never a
|
||||
// valid location expression.
|
||||
type Call struct {
|
||||
Pos lexer.Position
|
||||
Function Expression `parser:" '[' @@ "`
|
||||
Arguments []Expression `parser:" @@* ']' "`
|
||||
}
|
||||
func (*Call) expression(){}
|
||||
func (this *Call) String () string {
|
||||
out := fmt.Sprint("[", this.Function)
|
||||
for _, argument := range this.Arguments {
|
||||
out += fmt.Sprint(" ", argument)
|
||||
}
|
||||
return out + "]"
|
||||
}
|
||||
|
||||
// Array subscripting allows referring to a specific element of an array. It
|
||||
// accepts any array, and any offset of type Size. It may be assigned to any
|
||||
// type matching the array's element type. Since it contains inherent type
|
||||
// information, it may be directly assigned to an interface. A subscript is a
|
||||
// valid location expression only if the array being subscripted is.
|
||||
type Subscript struct {
|
||||
Pos lexer.Position
|
||||
Array Expression `parser:" '[' '.' @@ "`
|
||||
Offset Expression `parser:" @@ ']' "`
|
||||
}
|
||||
func (*Subscript) expression(){}
|
||||
func (this *Subscript) String () string {
|
||||
return fmt.Sprint("[.", this.Array, this.Offset, "]")
|
||||
}
|
||||
|
||||
// Pointer dereferencing allows retrieving the value of a pointer. It accepts
|
||||
// any pointer. It may be assigned to any type matching the pointer's pointed
|
||||
// type. Since it contains inherent type information, it may be directly
|
||||
// assigned to an interface. A dereference is a valid location expression only
|
||||
// if the pointer being dereferenced is.
|
||||
type Dereference struct {
|
||||
Pos lexer.Position
|
||||
Pointer Expression `parser:" '[' '.' @@ ']' "`
|
||||
}
|
||||
func (*Dereference) expression(){}
|
||||
func (this *Dereference) String () string {
|
||||
return fmt.Sprint("[.", this.Pointer, "]")
|
||||
}
|
||||
|
||||
// Value referencing allows retrieving the location of a value in memory. It
|
||||
// accepts any location expression, and can be assigned to any type that is a
|
||||
// pointer to the location expression's type. Since it contains inherent type
|
||||
// information, it can be directly assigned to an interface, although it doesn't
|
||||
// make a whole lot of sense to do so because assigning a value to an interface
|
||||
// automatically references it anyway. A reference is never a valid location
|
||||
// expression.
|
||||
type Reference struct {
|
||||
Pos lexer.Position
|
||||
Value Expression `parser:" '[' '@' @@ ']' "`
|
||||
}
|
||||
func (*Reference) expression(){}
|
||||
func (this *Reference) String () string {
|
||||
return fmt.Sprint("[@", this.Value, "]")
|
||||
}
|
||||
|
||||
// Vaue casting converts a value of a certain type to another type. Since it
|
||||
// contains inherent type information, it may be directly assigned to an
|
||||
// interface. A value cast is never a valid location expression.
|
||||
type ValueCast struct {
|
||||
Pos lexer.Position
|
||||
Type Expression `parser:" '[' 'cast' @@ "`
|
||||
Value Expression `parser:" @@ ']' "`
|
||||
}
|
||||
func (*ValueCast) expression(){}
|
||||
func (this *ValueCast) String () string {
|
||||
return fmt.Sprint("[cast", this.Type, this.Value, "]")
|
||||
}
|
||||
|
||||
// Bit casting takes the raw data in memory of a certain value and re-interprets
|
||||
// it as a value of another type. Since it contains inherent type information,
|
||||
// it may be directly assigned to an interface. A bit cast is never a valid
|
||||
// location expression.
|
||||
type BitCast struct {
|
||||
Pos lexer.Position
|
||||
Type Expression `parser:" '[' 'bitcast' @@ "`
|
||||
Value Expression `parser:" @@ ']' "`
|
||||
}
|
||||
func (*BitCast) expression(){}
|
||||
func (this *BitCast) String () string {
|
||||
return fmt.Sprint("[bitcast", this.Type, this.Value, "]")
|
||||
}
|
||||
|
||||
// Operations perform math, logic, or bit manipulation on values. They accept
|
||||
// values of the same type as the type they are being assigned to, except in
|
||||
// special cases. Since they contain no inherent type information, they may not
|
||||
// be assigned to interfaces. An operation is never a valid location expression.
|
||||
type Operation struct {
|
||||
Pos lexer.Position
|
||||
Operator string `parser:" '[' @('+' | '++' | '-' | '--' | '*' | '/' |
|
||||
'%' | '!!' | '||' | '&&' | '^^' | '!' |
|
||||
'|' | '&' | '^' | '<<' | '>>' | '<' |
|
||||
'>' | '<=' | '>=' | '=') "`
|
||||
Arguments []Expression `parser:" @@+ ']' "`
|
||||
}
|
||||
func (*Operation) expression(){}
|
||||
func (this *Operation) String () string {
|
||||
out := "[" + this.Operator
|
||||
for _, argument := range this.Arguments {
|
||||
out += fmt.Sprint(" ", argument)
|
||||
}
|
||||
return out + "]"
|
||||
}
|
||||
|
||||
// Block is an ordered collection of expressions that are evaluated
|
||||
// sequentially. It has its own scope. The last expression in the block
|
||||
// specifies the block's value, and any assignment rules of the block are
|
||||
// equivalent to those of its last expression. A block is never a valid location
|
||||
// expression.
|
||||
type Block struct {
|
||||
Pos lexer.Position
|
||||
Steps []Expression `parser:" '{' @@* '}' "`
|
||||
}
|
||||
func (*Block) expression(){}
|
||||
func (this *Block) String () string {
|
||||
out := "{"
|
||||
for _, step := range this.Steps {
|
||||
out += fmt.Sprint(" ", step)
|
||||
}
|
||||
return out + "}"
|
||||
}
|
||||
|
||||
// Member access allows referring to a specific member of a value with a struct
|
||||
// type. It accepts any struct type that contains the specified member name, and
|
||||
// may be assigned to any type that matches the type of the selected member.
|
||||
// Since it contains inherent type information, it may be directly assigned to
|
||||
// an interface. A member access is a valid location expression only when the
|
||||
// struct being accessed is.
|
||||
type MemberAccess struct {
|
||||
Pos lexer.Position
|
||||
Source Expression `parser:" @@ "`
|
||||
Member string `parser:" '.' @@ "`
|
||||
}
|
||||
func (*MemberAccess) expression(){}
|
||||
func (this *MemberAccess) String () string {
|
||||
return fmt.Sprint(this.Source, ".", this.Member)
|
||||
}
|
||||
|
||||
// Method access allows referring to a specific method of a type, or a behavior
|
||||
// of an interface. It can only be assigned to the first argument of a call. A
|
||||
// method access is never a valid location expression.
|
||||
type MethodAccess struct {
|
||||
Pos lexer.Position
|
||||
Source Expression `parser:" @@ "`
|
||||
Member string `parser:" '::' @@ "`
|
||||
}
|
||||
func (*MethodAccess) expression(){}
|
||||
func (this *MethodAccess) String () string {
|
||||
return fmt.Sprint(this.Source, "::", this.Member)
|
||||
}
|
||||
|
||||
// If/else is a control flow branching expression that executes one of two
|
||||
// expressions depending on a boolean value. If the value of the if/else is
|
||||
// unused, the else expression need not be specified. It may be assigned to any
|
||||
// type that satisfies the assignment rules of both the true and false
|
||||
// expressions. An If/else is never a valid location expression.
|
||||
type IfElse struct {
|
||||
Pos lexer.Position
|
||||
Condition Expression `parser:" 'if' @@ "`
|
||||
True Expression `parser:" 'then' @@ "`
|
||||
False Expression `parser:" ('else' @@)? "`
|
||||
}
|
||||
func (*IfElse) expression(){}
|
||||
func (this *IfElse) String () string {
|
||||
out := fmt.Sprint("if", this.Condition, "then", this.True)
|
||||
if this.False != nil {
|
||||
out += fmt.Sprint(" ", this.False)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Loop is a control flow expression that repeats an expression until a break
|
||||
// statement is called from within it. The break statement must be given a value
|
||||
// if the value of the loop is used. Otherwise, it need not even have a break
|
||||
// statement. The result of the loop may be assigned to any type that satisfies
|
||||
// the assignment rules of all of its break statements. Loops may be nested, and
|
||||
// break statements only apply to the closest containing loop. The value of the
|
||||
// loop's expression is never used. A loop is never a valid location expression.
|
||||
type Loop struct {
|
||||
Pos lexer.Position
|
||||
Body Expression `parser:" 'loop' @@ "`
|
||||
}
|
||||
func (*Loop) expression(){}
|
||||
func (this *Loop) String () string {
|
||||
return fmt.Sprint("loop", this.Body)
|
||||
}
|
||||
|
||||
// Break allows breaking out of loops. It has no value and may not be assigned
|
||||
// to anything. It is never a valid location expression.
|
||||
type Break struct {
|
||||
Pos lexer.Position
|
||||
Value Expression `parser:" '[' 'break' @@? " ']'`
|
||||
}
|
||||
func (*Break) expression(){}
|
||||
func (this *Break) String () string {
|
||||
return fmt.Sprint("break", this.Value)
|
||||
}
|
||||
// Return allows terminating functions before they have reached their end. It
|
||||
// accepts values that may be assigned to the function's return type. If a
|
||||
// function does not return anything, the return statement does not accept a
|
||||
// value. In all cases, return statements have no value and may not be assigned
|
||||
// to anything. A return statement is never a valid location expression.
|
||||
type Return struct {
|
||||
Pos lexer.Position
|
||||
Value Expression `parser:" '[' 'return' @@? " ']'`
|
||||
}
|
||||
func (*Return) expression(){}
|
||||
func (this *Return) String () string {
|
||||
return fmt.Sprint("return", this.Value)
|
||||
}
|
||||
|
||||
// Assignment allows assigning the result of one expression to one or more
|
||||
// location expressions. The assignment statement itself has no value and may
|
||||
// not be assigned to anything. An assignment statement is never a valid
|
||||
// location expression.
|
||||
type Assignment struct {
|
||||
Pos lexer.Position
|
||||
Location Expression `parser:" @@ "`
|
||||
Value Expression `parser:" '=' @@ "`
|
||||
}
|
||||
func (*Assignment) expression(){}
|
||||
func (this *Assignment) String () string {
|
||||
return fmt.Sprint(this.Location, "=", this.Value)
|
||||
}
|
||||
71
parser/literal.go
Normal file
71
parser/literal.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package parser
|
||||
|
||||
import "fmt"
|
||||
import "github.com/alecthomas/participle/v2/lexer"
|
||||
|
||||
// LiteralInt specifies an integer value. It can be assigned to any type that is
|
||||
// derived from an integer, or a float. It cannot be directly assigned to an
|
||||
// interface because it contains no inherent type information. A value cast may
|
||||
// be used for this purpose.
|
||||
type LiteralInt struct {
|
||||
Pos lexer.Position
|
||||
Value int `parser:" @Int "`
|
||||
}
|
||||
func (*LiteralInt) expression(){}
|
||||
func (this *LiteralInt) String () string {
|
||||
return fmt.Sprint(this.Value)
|
||||
}
|
||||
|
||||
// LiteralFloat specifies a floating point value. It can be assigned to any type
|
||||
// that is derived from a float. It cannot be directly assigned to an interface
|
||||
// because it contains no inherent type information. A value cast may be used
|
||||
// for this purpose.
|
||||
type LiteralFloat struct {
|
||||
Pos lexer.Position
|
||||
Value float64 `parser:" @Float "`
|
||||
}
|
||||
func (*LiteralFloat) expression(){}
|
||||
func (this *LiteralFloat) String () string {
|
||||
return fmt.Sprint(this.Value)
|
||||
}
|
||||
|
||||
// Array is a composite array literal. It can contain any number of values. It
|
||||
// can be assigned to any array type that:
|
||||
// 1. has an identical length, and
|
||||
// 2. who's element type can be assigned to by all the element values in the
|
||||
// literal.
|
||||
// It cannot be directly assigned to an interface because it contains no
|
||||
// inherent type information. A value cast may be used for this purpose.
|
||||
type LiteralArray struct {
|
||||
Pos lexer.Position
|
||||
Elements []Expression `parser:" '(' '*' @@* ')' "`
|
||||
}
|
||||
func (*LiteralArray) expression(){}
|
||||
func (this *LiteralArray) String () string {
|
||||
out := "(*"
|
||||
for _, element := range this.Elements {
|
||||
out += fmt.Sprint(" ", element)
|
||||
}
|
||||
return out + ")"
|
||||
}
|
||||
|
||||
// Struct is a composite structure literal. It can contain any number of
|
||||
// name:value pairs. It can be assigned to any struct type that:
|
||||
// 1. has at least the members specified in the literal
|
||||
// 2. who's member types can be assigned to by the corresponding member
|
||||
// values in the literal.
|
||||
// It cannot be directly assigned to an interface because it contains no
|
||||
// inherent type information. A value cast may be used for this purpose.
|
||||
type LiteralStruct struct {
|
||||
Pos lexer.Position
|
||||
Members []Member `parser:" '(' @@* ')' "`
|
||||
}
|
||||
func (*LiteralStruct) expression(){}
|
||||
func (this *LiteralStruct) String () string {
|
||||
out := "("
|
||||
for index, member := range this.Members {
|
||||
if index > 1 { out += " " }
|
||||
out += fmt.Sprint(member)
|
||||
}
|
||||
return out + ")"
|
||||
}
|
||||
37
parser/misc.go
Normal file
37
parser/misc.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package parser
|
||||
|
||||
import "fmt"
|
||||
import "github.com/alecthomas/participle/v2/lexer"
|
||||
|
||||
// Signature is a function or method signature that is used in functions,
|
||||
// methods, and specifying interface behaviors. It defines the type of a
|
||||
// function.
|
||||
type Signature struct {
|
||||
Pos lexer.Position
|
||||
Name string `parser:" '[' @Ident "`
|
||||
Arguments []Declaration `parser:" @@* ']' "`
|
||||
Return Type `parser:" ( ':' @@ )? "`
|
||||
}
|
||||
func (*Signature) ty(){}
|
||||
func (this *Signature) String () string {
|
||||
out := "[" + this.Name
|
||||
for _, argument := range this.Arguments {
|
||||
out += fmt.Sprint(" ", argument)
|
||||
}
|
||||
out += "]"
|
||||
if this.Return != nil {
|
||||
out += fmt.Sprint(": ", this.Return)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Member is a syntactical construct that is used to list members in struct
|
||||
// literals.
|
||||
type Member struct {
|
||||
Pos lexer.Position
|
||||
Name string `parser:" @Ident "`
|
||||
Value Expression `parser:" ':' @@ "`
|
||||
}
|
||||
func (this *Member) String () string {
|
||||
return fmt.Sprint(this.Name, ":", this.Value)
|
||||
}
|
||||
76
parser/toplevel.go
Normal file
76
parser/toplevel.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package parser
|
||||
|
||||
import "fmt"
|
||||
import "github.com/alecthomas/participle/v2/lexer"
|
||||
|
||||
// TopLevel is any construct that is placed at the root of a file.
|
||||
type TopLevel interface {
|
||||
topLevel ()
|
||||
}
|
||||
|
||||
// Typedef binds a type to a global identifier.
|
||||
type Typedef struct {
|
||||
// Syntax
|
||||
Pos lexer.Position
|
||||
Public bool `parser: " @'+'? "`
|
||||
Name string `parser: " @Ident "`
|
||||
Type Type `parser: " ':' @@ "`
|
||||
|
||||
// Semantics
|
||||
Methods map[string] Method
|
||||
}
|
||||
func (*Typedef) topLevel(){}
|
||||
func (this *Typedef) String () string {
|
||||
out := fmt.Sprint(this.Name, " : ", this.Type)
|
||||
if this.Methods != nil {
|
||||
for _, method := range this.Methods {
|
||||
out += fmt.Sprint("\n", method)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// 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
|
||||
Pos lexer.Position
|
||||
Public bool `parser: " @'+'? "`
|
||||
Signature `parser: " @@ "`
|
||||
Body Expression `parser: " ( '=' @@ )? "`
|
||||
}
|
||||
func (*Function) topLevel(){}
|
||||
func (this *Function) String () string {
|
||||
if this.Body == nil {
|
||||
return fmt.Sprint(this.Signature)
|
||||
} else {
|
||||
return fmt.Sprint(this.Signature, " = ", this.Body)
|
||||
}
|
||||
}
|
||||
|
||||
// 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. Method names are not globally unique, bur are unique
|
||||
// within the type they are defined on.
|
||||
type Method struct {
|
||||
// Syntax
|
||||
Pos lexer.Position
|
||||
Public bool `parser: " @'+'? "`
|
||||
TypeName string `parser: " @Ident "`
|
||||
Signature `parser: " '.' @@ "`
|
||||
Body Expression `parser: " ( '=' @@ )? "`
|
||||
}
|
||||
func (*Method) topLevel(){}
|
||||
func (this *Method) String () string {
|
||||
if this.Body == nil {
|
||||
return fmt.Sprint(this.TypeName, ".", this.Signature)
|
||||
} else {
|
||||
return fmt.Sprint (
|
||||
this.TypeName, ".",
|
||||
this.Signature, " = ",
|
||||
this.Body)
|
||||
}
|
||||
}
|
||||
51
parser/tree.go
Normal file
51
parser/tree.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package parser
|
||||
|
||||
import "io"
|
||||
import "github.com/alecthomas/participle/v2"
|
||||
|
||||
var parser = participle.MustBuild[Tree] (
|
||||
participle.Union[TopLevel] (
|
||||
&Function { },
|
||||
&Typedef { },
|
||||
&Method { }),
|
||||
participle.Union[Type] (
|
||||
&TypePointer { },
|
||||
&TypeInterface { },
|
||||
&TypeStruct { },
|
||||
&TypeArray { }),
|
||||
participle.Union[Expression] (
|
||||
&LiteralInt { },
|
||||
&LiteralFloat { },
|
||||
&LiteralArray { },
|
||||
&LiteralStruct { },
|
||||
&Variable { },
|
||||
&Declaration { },
|
||||
&Call { },
|
||||
&Subscript { },
|
||||
&Dereference { },
|
||||
&Reference { },
|
||||
&ValueCast { },
|
||||
&BitCast { },
|
||||
&Operation { },
|
||||
&Block { },
|
||||
&MemberAccess { },
|
||||
&MethodAccess { },
|
||||
&IfElse { },
|
||||
&Loop { },
|
||||
&Break { },
|
||||
&Return { },
|
||||
&Assignment { }),
|
||||
participle.UseLookahead(participle.MaxLookahead))
|
||||
|
||||
// Tree represents a parsed abstract syntax tree. It has no constructor and its
|
||||
// zero value can be used safely.
|
||||
type Tree struct {
|
||||
Declarations []TopLevel `parser:" @@* "`
|
||||
}
|
||||
|
||||
// Parse parses the contents of the given io.Reader into the tree.
|
||||
func (this *Tree) Parse (name string, file io.Reader) error {
|
||||
parsed, err := parser.Parse(name, file)
|
||||
this.Declarations = append(this.Declarations, parsed.Declarations...)
|
||||
return err
|
||||
}
|
||||
74
parser/type.go
Normal file
74
parser/type.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package parser
|
||||
|
||||
import "fmt"
|
||||
import "github.com/alecthomas/participle/v2/lexer"
|
||||
|
||||
// Type is any type notation.
|
||||
type Type interface {
|
||||
ty ()
|
||||
}
|
||||
|
||||
// TypeNamed refers to a user-defined or built in named type.
|
||||
type TypeNamed struct {
|
||||
Pos lexer.Position
|
||||
Name string `parser:" @Ident "`
|
||||
}
|
||||
func (*TypeNamed) ty(){}
|
||||
func (this *TypeNamed) String () string { return this.Name }
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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 'x' "`
|
||||
Element Type `parser:" @@ "`
|
||||
}
|
||||
func (*TypeArray) ty(){}
|
||||
func (this *TypeArray) String () string {
|
||||
return fmt.Sprint(this.Length, "x", this.Element)
|
||||
}
|
||||
|
||||
// Struct 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 {
|
||||
Pos lexer.Position
|
||||
Members []*Declaration `parser:" '(' @@+ ')' `
|
||||
}
|
||||
func (*TypeStruct) ty(){}
|
||||
func (this *TypeStruct) String () string {
|
||||
out := "("
|
||||
for _, member := range this.Members {
|
||||
out += fmt.Sprint(member)
|
||||
}
|
||||
return out + ")"
|
||||
}
|
||||
|
||||
// Interface 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 {
|
||||
Pos lexer.Position
|
||||
Behaviors []*Signature `parser:" '(' @@+ ')' "`
|
||||
}
|
||||
func (*TypeInterface) ty(){}
|
||||
func (this *TypeInterface) String () string {
|
||||
out := "("
|
||||
for _, behavior := range this.Behaviors {
|
||||
out += fmt.Sprint(behavior)
|
||||
}
|
||||
return out + ")"
|
||||
}
|
||||
Reference in New Issue
Block a user