Location expressions

This commit is contained in:
Sasha Koshka 2023-10-24 21:54:59 -04:00
parent bec91323b9
commit 2a5ffb12a1
10 changed files with 214 additions and 44 deletions

View File

@ -127,3 +127,77 @@ func (this *Tree) reduceToBase (ty entity.Type) entity.Type {
return ty return ty
} }
} }
// isLocationExpression returns whether or not an expression is a valid location
// expression.
func (this *Tree) isLocationExpression (expression entity.Expression) error {
switch expression.(type) {
case *entity.Variable:
return nil
case *entity.Declaration:
return nil
case *entity.Call:
return participle.Errorf (
expression.(*entity.Call).Pos,
"cannot assign to function call")
case *entity.MethodCall:
return participle.Errorf (
expression.(*entity.MethodCall).Pos,
"cannot assign to method call")
case *entity.Subscript:
return this.isLocationExpression (
expression.(*entity.Subscript).Slice)
case *entity.Slice:
return participle.Errorf (
expression.(*entity.MethodCall).Pos,
"cannot assign to slice operation")
case *entity.Dereference:
return this.isLocationExpression (
expression.(*entity.Dereference).Pointer)
case *entity.Reference:
return participle.Errorf (
expression.(*entity.Reference).Pos,
"cannot assign to reference operation")
case *entity.ValueCast:
return participle.Errorf (
expression.(*entity.ValueCast).Pos,
"cannot assign to value cast")
case *entity.BitCast:
return participle.Errorf (
expression.(*entity.BitCast).Pos,
"cannot assign to bit cast")
case *entity.Operation:
expression := expression.(*entity.Operation)
return participle.Errorf (
expression.Pos,
"cannot assign to %v operation",
expression.Operator)
case *entity.Block:
return participle.Errorf (
expression.(*entity.Block).Pos,
"cannot assign to block")
case *entity.MemberAccess:
return this.isLocationExpression (
expression.(*entity.MemberAccess).Source)
case *entity.IfElse:
return participle.Errorf (
expression.(*entity.Block).Pos,
"cannot assign to if/else")
case *entity.Loop:
return participle.Errorf (
expression.(*entity.Block).Pos,
"cannot assign to loop")
case *entity.Break:
return participle.Errorf (
expression.(*entity.Block).Pos,
"cannot assign to break statement")
case *entity.Return:
return participle.Errorf (
expression.(*entity.Block).Pos,
"cannot assign to return statement")
default:
panic(fmt.Sprint (
"BUG: analyzer doesnt know about expression ",
expression))
}
}

View File

@ -24,7 +24,7 @@ func (this *Tree) analyzeVariable (
variable.Name) variable.Name)
} }
err := this.canAssign(variable.Pos, into, mode, declaration.Type) err := this.canAssign(variable.Pos, into, mode, declaration.Type())
if err != nil { return nil, err } if err != nil { return nil, err }
variable.Declaration = declaration variable.Declaration = declaration
@ -47,11 +47,11 @@ func (this *Tree) analyzeDeclaration (
declaration.Name, existing.Pos) declaration.Name, existing.Pos)
} }
ty, err := this.analyzeType(declaration.Type, false) ty, err := this.analyzeType(declaration.Ty, false)
declaration.Type = ty declaration.Ty = ty
if err != nil { return nil, err } if err != nil { return nil, err }
err = this.canAssign(declaration.Pos, into, mode, declaration.Type) err = this.canAssign(declaration.Pos, into, mode, declaration.Type())
if err != nil { return nil, err } if err != nil { return nil, err }
this.AddVariable(declaration) this.AddVariable(declaration)
@ -94,7 +94,7 @@ func (this *Tree) analyzeCall (
for index, argument := range call.Arguments { for index, argument := range call.Arguments {
signature := function.Signature signature := function.Signature
correct := signature.ArgumentMap[signature.ArgumentOrder[index]] correct := signature.ArgumentMap[signature.ArgumentOrder[index]]
argument, err := this.analyzeExpression(correct.Type, strict, argument) argument, err := this.analyzeExpression(correct.Type(), strict, argument)
if err != nil { return nil, err } if err != nil { return nil, err }
call.Arguments[index] = argument call.Arguments[index] = argument
} }
@ -115,7 +115,7 @@ func (this *Tree) analyzeMethodCall (
source := sourceExpr.(*entity.Variable) source := sourceExpr.(*entity.Variable)
if err != nil { return nil, err } if err != nil { return nil, err }
method, err := this.analyzeMethodOrBehavior ( method, err := this.analyzeMethodOrBehavior (
call.Pos, source.Declaration.Type, call.Name) call.Pos, source.Declaration.Type(), call.Name)
// extract signature // extract signature
var signature *entity.Signature var signature *entity.Signature
@ -150,7 +150,7 @@ func (this *Tree) analyzeMethodCall (
// check arg types // check arg types
for index, argument := range call.Arguments { for index, argument := range call.Arguments {
correct := signature.ArgumentMap[signature.ArgumentOrder[index]] correct := signature.ArgumentMap[signature.ArgumentOrder[index]]
argument, err := this.analyzeExpression(correct.Type, strict, argument) argument, err := this.analyzeExpression(correct.Type(), strict, argument)
if err != nil { return nil, err } if err != nil { return nil, err }
call.Arguments[index] = argument call.Arguments[index] = argument
} }
@ -174,6 +174,7 @@ func (this *Tree) analyzeSubscript (
subscript.Slice) subscript.Slice)
if err != nil { return nil, err } if err != nil { return nil, err }
subscript.Slice = slice subscript.Slice = slice
subscript.Ty = into
offset, err := this.analyzeExpression ( offset, err := this.analyzeExpression (
builtinType("index"), weak, builtinType("index"), weak,
@ -192,9 +193,9 @@ func (this *Tree) analyzeSlice (
entity.Expression, entity.Expression,
error, error,
) { ) {
slice, err := this.analyzeExpression(into, weak, slice.Slice) value, err := this.analyzeExpression(into, weak, slice.Slice)
if err != nil { return nil, err } if err != nil { return nil, err }
slice.Slice = slice slice.Slice = value
if slice.Start != nil { if slice.Start != nil {
start, err := this.analyzeExpression ( start, err := this.analyzeExpression (
@ -225,12 +226,13 @@ func (this *Tree) analyzeDereference (
) { ) {
pointer, err := this.analyzeExpression ( pointer, err := this.analyzeExpression (
&entity.TypePointer { &entity.TypePointer {
Pos: subscript.Pos, Pos: dereference.Pos,
Referenced: into, Referenced: into,
}, weak, }, weak,
dereference.Pointer) dereference.Pointer)
if err != nil { return nil, err } if err != nil { return nil, err }
dereference.Pointer = pointer dereference.Pointer = pointer
dereference.Ty = into
return pointer, nil return pointer, nil
} }
@ -243,15 +245,19 @@ func (this *Tree) analyzeReference (
entity.Expression, entity.Expression,
error, error,
) { ) {
reference, ok := into.(*entity.TypePointer) referenced, ok := into.(*entity.TypePointer)
if !ok { return nil, participle.Errorf(pos, "expected %v", into) } if !ok {
return nil, participle.Errorf(reference.Pos, "expected %v", into)
}
value, err := this.analyzeExpression ( value, err := this.analyzeExpression (
referenced.Referenced, referenced.Referenced, weak,
reference.Pointer) reference.Value)
if err != nil { return nil, err }
err = this.isLocationExpression(reference.Value)
if err != nil { return nil, err } if err != nil { return nil, err }
// TODO error if value is not a location expression
reference.Value = value reference.Value = value
reference.Ty = into
return pointer, nil return reference, nil
} }

View File

@ -34,7 +34,7 @@ func (this *Tree) analyzeFunction (
function.Signature, err = this.assembleSignatureMap(function.Signature) function.Signature, err = this.assembleSignatureMap(function.Signature)
if err != nil { return function, err } if err != nil { return function, err }
for name, argument := range function.Signature.ArgumentMap { for name, argument := range function.Signature.ArgumentMap {
argument.Type, err = this.analyzeType(argument.Type, false) argument.Ty, err = this.analyzeType(argument.Ty, false)
this.AddVariable(argument) this.AddVariable(argument)
function.Signature.ArgumentMap[name] = argument function.Signature.ArgumentMap[name] = argument
if err != nil { return function, err } if err != nil { return function, err }

View File

@ -41,7 +41,7 @@ func (this *Tree) analyzeMethod (
method.Signature, err = this.assembleSignatureMap(method.Signature) method.Signature, err = this.assembleSignatureMap(method.Signature)
if err != nil { return method, err } if err != nil { return method, err }
for name, argument := range method.Signature.ArgumentMap { for name, argument := range method.Signature.ArgumentMap {
argument.Type, err = this.analyzeType(argument.Type, false) argument.Ty, err = this.analyzeType(argument.Ty, false)
this.AddVariable(argument) this.AddVariable(argument)
method.Signature.ArgumentMap[name] = argument method.Signature.ArgumentMap[name] = argument
if err != nil { return method, err } if err != nil { return method, err }

View File

@ -5,15 +5,24 @@ package analyzer
import "git.tebibyte.media/sashakoshka/fspl/entity" import "git.tebibyte.media/sashakoshka/fspl/entity"
func (this *Tree) analyzeAssignment ( func (this *Tree) analyzeAssignment (
variable *entity.Assignment, assignment *entity.Assignment,
) ( ) (
entity.Statement, entity.Statement,
error, error,
) { ) {
// TODO // analyze location
// 1. analyze location location, err := this.analyzeExpression(nil, strict, assignment.Location)
// 2. ensure location is location expression if err != nil { return nil, err }
// 3. analyze value assignment.Location = location
return nil, nil
}
// ensure location is location expression
err = this.isLocationExpression(location)
if err != nil { return nil, err }
// analyze value
value, err := this.analyzeExpression(location.Type(), strict, assignment.Value)
if err != nil { return nil, err }
assignment.Value = value
return assignment, nil
}

View File

@ -123,8 +123,8 @@ func (this *Tree) analyzeTypeInternal (
updateIncompleteInfo() updateIncompleteInfo()
if err != nil { return ty, err } if err != nil { return ty, err }
for name, member := range ty.MemberMap { for name, member := range ty.MemberMap {
ty.MemberMap[name].Type, ty.MemberMap[name].Ty,
err = this.analyzeType(member.Type, false) err = this.analyzeType(member.Ty, false)
if err != nil { return ty, err } if err != nil { return ty, err }
} }
return ty, nil return ty, nil
@ -195,7 +195,7 @@ func (this *Tree) analyzeBehavior (behavior *entity.Signature) (*entity.Signatur
behavior, err := this.assembleSignatureMap(behavior) behavior, err := this.assembleSignatureMap(behavior)
if err != nil { return behavior, nil } if err != nil { return behavior, nil }
for name, argument := range behavior.ArgumentMap { for name, argument := range behavior.ArgumentMap {
behavior.ArgumentMap[name].Type, err = this.analyzeType(argument.Type, false) behavior.ArgumentMap[name].Ty, err = this.analyzeType(argument.Ty, false)
if err != nil { return behavior, err } if err != nil { return behavior, err }
} }
behavior.Return, err = this.analyzeType(behavior.Return, false) behavior.Return, err = this.analyzeType(behavior.Return, false)

View File

@ -5,8 +5,10 @@ import "github.com/alecthomas/participle/v2/lexer"
// Expression is any construct that can be evaluated. // Expression is any construct that can be evaluated.
type Expression interface { type Expression interface {
expression ()
Statement Statement
Type () Type
expression ()
} }
// Statement is any construct that can be placed inside of a block expression. // Statement is any construct that can be placed inside of a block expression.
@ -28,6 +30,7 @@ type Variable struct {
} }
func (*Variable) expression(){} func (*Variable) expression(){}
func (*Variable) statement(){} func (*Variable) statement(){}
func (this *Variable) Type () Type { return this.Declaration.Type() }
func (this *Variable) String () string { func (this *Variable) String () string {
return this.Name return this.Name
} }
@ -40,10 +43,11 @@ func (this *Variable) String () string {
type Declaration struct { type Declaration struct {
Pos lexer.Position Pos lexer.Position
Name string `parser:" @Ident "` Name string `parser:" @Ident "`
Type Type `parser:" ':' @@ "` Ty Type `parser:" ':' @@ "`
} }
func (*Declaration) expression(){} func (*Declaration) expression(){}
func (*Declaration) statement(){} func (*Declaration) statement(){}
func (this *Declaration) Type () Type { return this.Ty }
func (this *Declaration) String () string { func (this *Declaration) String () string {
return fmt.Sprint(this.Name, ":", this.Type) return fmt.Sprint(this.Name, ":", this.Type)
} }
@ -56,7 +60,7 @@ func (this *Declaration) String () string {
// expression. // expression.
type Call struct { type Call struct {
// Syntax // Syntax
Pos lexer.Position Pos lexer.Position
Name string `parser:" '[' @Ident "` Name string `parser:" '[' @Ident "`
Arguments []Expression `parser:" @@* ']' "` Arguments []Expression `parser:" @@* ']' "`
@ -65,6 +69,7 @@ type Call struct {
} }
func (*Call) expression(){} func (*Call) expression(){}
func (*Call) statement(){} func (*Call) statement(){}
func (this *Call) Type () Type { return this.Function.Signature.Return }
func (this *Call) String () string { func (this *Call) String () string {
out := fmt.Sprint("[", this.Name) out := fmt.Sprint("[", this.Name)
for _, argument := range this.Arguments { for _, argument := range this.Arguments {
@ -81,7 +86,7 @@ func (this *Call) String () string {
// A method call is never a valid location expression. // A method call is never a valid location expression.
type MethodCall struct { type MethodCall struct {
// Syntax // Syntax
Pos lexer.Position Pos lexer.Position
Source *Variable `parser:" @@ '.' "` Source *Variable `parser:" @@ '.' "`
Name string `parser:" '[' @Ident "` Name string `parser:" '[' @Ident "`
Arguments []Expression `parser:" @@* ']' "` Arguments []Expression `parser:" @@* ']' "`
@ -89,9 +94,17 @@ type MethodCall struct {
// Semantics // Semantics
Method *Method Method *Method
Behavior *Signature Behavior *Signature
Ty Type
} }
func (*MethodCall) expression(){} func (*MethodCall) expression(){}
func (*MethodCall) statement(){} func (*MethodCall) statement(){}
func (this *MethodCall) Type () Type {
if this.Method != nil {
return this.Method.Signature.Return
} else {
return this.Behavior.Return
}
}
func (this *MethodCall) String () string { func (this *MethodCall) String () string {
out := fmt.Sprint(this.Source, ".[", this.Name) out := fmt.Sprint(this.Source, ".[", this.Name)
for _, argument := range this.Arguments { for _, argument := range this.Arguments {
@ -106,12 +119,17 @@ func (this *MethodCall) String () string {
// information, it may be directly assigned to an interface. A subscript is a // information, it may be directly assigned to an interface. A subscript is a
// valid location expression only if the array being subscripted is. // valid location expression only if the array being subscripted is.
type Subscript struct { type Subscript struct {
Pos lexer.Position // Syntax
Slice Expression `parser:" '[' '.' @@ "` Pos lexer.Position
Offset Expression `parser:" @@ ']' "` Slice Expression `parser:" '[' '.' @@ "`
Offset Expression `parser:" @@ ']' "`
// Semantics
Ty Type
} }
func (*Subscript) expression(){} func (*Subscript) expression(){}
func (*Subscript) statement(){} func (*Subscript) statement(){}
func (this *Subscript) Type () Type { return this.Ty }
func (this *Subscript) String () string { func (this *Subscript) String () string {
return fmt.Sprint("[.", this.Slice, " ", this.Offset, "]") return fmt.Sprint("[.", this.Slice, " ", this.Offset, "]")
} }
@ -121,13 +139,15 @@ func (this *Subscript) String () string {
// assignment rules of this expression are equivalent to those of the slice it // assignment rules of this expression are equivalent to those of the slice it
// is operating on. A slice is never a valid location expression. // is operating on. A slice is never a valid location expression.
type Slice struct { type Slice struct {
Pos lexer.Position // Syntax
Pos lexer.Position
Slice Expression `parser:" '[' '\\\\' @@ "` Slice Expression `parser:" '[' '\\\\' @@ "`
Start Expression `parser:" @@? "` Start Expression `parser:" @@? "`
End Expression `parser:" ':' @@? ']' "` End Expression `parser:" ':' @@? ']' "`
} }
func (*Slice) expression(){} func (*Slice) expression(){}
func (*Slice) statement(){} func (*Slice) statement(){}
func (this *Slice) Type () Type { return this.Slice.Type() }
func (this *Slice) String () string { func (this *Slice) String () string {
out := fmt.Sprint("[\\", this.Slice, " ") out := fmt.Sprint("[\\", this.Slice, " ")
if this.Start != nil { if this.Start != nil {
@ -146,11 +166,16 @@ func (this *Slice) String () string {
// assigned to an interface. A dereference is a valid location expression only // assigned to an interface. A dereference is a valid location expression only
// if the pointer being dereferenced is. // if the pointer being dereferenced is.
type Dereference struct { type Dereference struct {
Pos lexer.Position // Syntax
Pos lexer.Position
Pointer Expression `parser:" '[' '.' @@ ']' "` Pointer Expression `parser:" '[' '.' @@ ']' "`
// Semantics
Ty Type
} }
func (*Dereference) expression(){} func (*Dereference) expression(){}
func (*Dereference) statement(){} func (*Dereference) statement(){}
func (this *Dereference) Type () Type { return this.Ty }
func (this *Dereference) String () string { func (this *Dereference) String () string {
return fmt.Sprint("[.", this.Pointer, "]") return fmt.Sprint("[.", this.Pointer, "]")
} }
@ -163,11 +188,16 @@ func (this *Dereference) String () string {
// automatically references it anyway. A reference is never a valid location // automatically references it anyway. A reference is never a valid location
// expression. // expression.
type Reference struct { type Reference struct {
Pos lexer.Position // Syntax
Pos lexer.Position
Value Expression `parser:" '[' '@' @@ ']' "` Value Expression `parser:" '[' '@' @@ ']' "`
// Semantics
Ty Type
} }
func (*Reference) expression(){} func (*Reference) expression(){}
func (*Reference) statement(){} func (*Reference) statement(){}
func (this *Reference) Type () Type { return this.Ty }
func (this *Reference) String () string { func (this *Reference) String () string {
return fmt.Sprint("[@", this.Value, "]") return fmt.Sprint("[@", this.Value, "]")
} }
@ -176,12 +206,13 @@ func (this *Reference) String () string {
// contains inherent type information, it may be directly assigned to an // contains inherent type information, it may be directly assigned to an
// interface. A value cast is never a valid location expression. // interface. A value cast is never a valid location expression.
type ValueCast struct { type ValueCast struct {
Pos lexer.Position Pos lexer.Position
Type Type `parser:" '[' '~' @@ "` Ty Type `parser:" '[' '~' @@ "`
Value Expression `parser:" @@ ']' "` Value Expression `parser:" @@ ']' "`
} }
func (*ValueCast) expression(){} func (*ValueCast) expression(){}
func (*ValueCast) statement(){} func (*ValueCast) statement(){}
func (this *ValueCast) Type () Type { return this.Ty }
func (this *ValueCast) String () string { func (this *ValueCast) String () string {
return fmt.Sprint("[~ ", this.Type, this.Value, "]") return fmt.Sprint("[~ ", this.Type, this.Value, "]")
} }
@ -191,12 +222,13 @@ func (this *ValueCast) String () string {
// it may be directly assigned to an interface. A bit cast is never a valid // it may be directly assigned to an interface. A bit cast is never a valid
// location expression. // location expression.
type BitCast struct { type BitCast struct {
Pos lexer.Position Pos lexer.Position
Type Type `parser:" '[' '~~' @@ "` Ty Type `parser:" '[' '~~' @@ "`
Value Expression `parser:" @@ ']' "` Value Expression `parser:" @@ ']' "`
} }
func (*BitCast) expression(){} func (*BitCast) expression(){}
func (*BitCast) statement(){} func (*BitCast) statement(){}
func (this *BitCast) Type () Type { return this.Ty }
func (this *BitCast) String () string { func (this *BitCast) String () string {
return fmt.Sprint("[~~ ", this.Type, this.Value, "]") return fmt.Sprint("[~~ ", this.Type, this.Value, "]")
} }
@ -206,12 +238,17 @@ func (this *BitCast) String () string {
// special cases. Since they contain no inherent type information, they may not // special cases. Since they contain no inherent type information, they may not
// be assigned to interfaces. An operation is never a valid location expression. // be assigned to interfaces. An operation is never a valid location expression.
type Operation struct { type Operation struct {
// Syntax
Pos lexer.Position Pos lexer.Position
Operator Operator `parser:" '[' @('++' | '+' | '--' | '-' | '*' | '/' | '%' | '!!' | '||' | '&&' | '^^' | '!' | '|' | '&' | '^' | '<<' | '>>' | '<' | '>' | '<=' | '>=' | '=') "` Operator Operator `parser:" '[' @('++' | '+' | '--' | '-' | '*' | '/' | '%' | '!!' | '||' | '&&' | '^^' | '!' | '|' | '&' | '^' | '<<' | '>>' | '<' | '>' | '<=' | '>=' | '=') "`
Arguments []Expression `parser:" @@+ ']' "` Arguments []Expression `parser:" @@+ ']' "`
// Semantics
Ty Type
} }
func (*Operation) expression(){} func (*Operation) expression(){}
func (*Operation) statement(){} func (*Operation) statement(){}
func (this *Operation) Type () Type { return this.Ty }
func (this *Operation) String () string { func (this *Operation) String () string {
out := fmt.Sprint("[", this.Operator) out := fmt.Sprint("[", this.Operator)
for _, argument := range this.Arguments { for _, argument := range this.Arguments {
@ -231,10 +268,12 @@ type Block struct {
Steps []Statement `parser:" '{' @@* '}' "` Steps []Statement `parser:" '{' @@* '}' "`
// Semantics // Semantics
Ty Type
Scope Scope
} }
func (*Block) expression(){} func (*Block) expression(){}
func (*Block) statement(){} func (*Block) statement(){}
func (this *Block) Type () Type { return this.Ty }
func (this *Block) String () string { func (this *Block) String () string {
out := "{" out := "{"
for index, step := range this.Steps { for index, step := range this.Steps {
@ -251,12 +290,17 @@ func (this *Block) String () string {
// an interface. A member access is a valid location expression only when the // an interface. A member access is a valid location expression only when the
// struct being accessed is. // struct being accessed is.
type MemberAccess struct { type MemberAccess struct {
// Syntax
Pos lexer.Position Pos lexer.Position
Source *Variable `parser:" @@ "` Source *Variable `parser:" @@ "`
Member string `parser:" '.' @Ident "` Member string `parser:" '.' @Ident "`
// Semantics
Ty Type
} }
func (*MemberAccess) expression(){} func (*MemberAccess) expression(){}
func (*MemberAccess) statement(){} func (*MemberAccess) statement(){}
func (this *MemberAccess) Type () Type { return this.Ty }
func (this *MemberAccess) String () string { func (this *MemberAccess) String () string {
return fmt.Sprint(this.Source, ".", this.Member) return fmt.Sprint(this.Source, ".", this.Member)
} }
@ -267,13 +311,18 @@ func (this *MemberAccess) String () string {
// type that satisfies the assignment rules of both the true and false // type that satisfies the assignment rules of both the true and false
// expressions. An If/else is never a valid location expression. // expressions. An If/else is never a valid location expression.
type IfElse struct { type IfElse struct {
// Syntax
Pos lexer.Position Pos lexer.Position
Condition Expression `parser:" 'if' @@ "` Condition Expression `parser:" 'if' @@ "`
True Expression `parser:" 'then' @@ "` True Expression `parser:" 'then' @@ "`
False Expression `parser:" ('else' @@)? "` False Expression `parser:" ('else' @@)? "`
// Semantics
Ty Type
} }
func (*IfElse) expression(){} func (*IfElse) expression(){}
func (*IfElse) statement(){} func (*IfElse) statement(){}
func (this *IfElse) Type () Type { return this.Ty }
func (this *IfElse) String () string { func (this *IfElse) String () string {
out := fmt.Sprint("if ", this.Condition, " then ", this.True) out := fmt.Sprint("if ", this.Condition, " then ", this.True)
if this.False != nil { if this.False != nil {
@ -290,11 +339,16 @@ func (this *IfElse) String () string {
// break statements only apply to the closest containing loop. The value of the // 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. // loop's expression is never used. A loop is never a valid location expression.
type Loop struct { type Loop struct {
// Syntax
Pos lexer.Position Pos lexer.Position
Body Expression `parser:" 'loop' @@ "` Body Expression `parser:" 'loop' @@ "`
// Semantics
Ty Type
} }
func (*Loop) expression(){} func (*Loop) expression(){}
func (*Loop) statement(){} func (*Loop) statement(){}
func (this *Loop) Type () Type { return this.Ty }
func (this *Loop) String () string { func (this *Loop) String () string {
return fmt.Sprint("loop ", this.Body) return fmt.Sprint("loop ", this.Body)
} }
@ -307,6 +361,7 @@ type Break struct {
} }
func (*Break) expression(){} func (*Break) expression(){}
func (*Break) statement(){} func (*Break) statement(){}
func (this *Break) Type () Type { return &TypeVoid { } }
func (this *Break) String () string { func (this *Break) String () string {
if this.Value == nil { if this.Value == nil {
return "[break]" return "[break]"
@ -325,6 +380,7 @@ type Return struct {
} }
func (*Return) expression(){} func (*Return) expression(){}
func (*Return) statement(){} func (*Return) statement(){}
func (this *Return) Type () Type { return &TypeVoid { } }
func (this *Return) String () string { func (this *Return) String () string {
if this.Value == nil { if this.Value == nil {
return "[return]" return "[return]"

View File

@ -8,11 +8,16 @@ import "github.com/alecthomas/participle/v2/lexer"
// interface because it contains no inherent type information. A value cast may // interface because it contains no inherent type information. A value cast may
// be used for this purpose. // be used for this purpose.
type LiteralInt struct { type LiteralInt struct {
// Syntax
Pos lexer.Position Pos lexer.Position
Value int `parser:" @Int "` Value int `parser:" @Int "`
// Semantics
Ty Type
} }
func (*LiteralInt) expression(){} func (*LiteralInt) expression(){}
func (*LiteralInt) statement(){} func (*LiteralInt) statement(){}
func (this *LiteralInt) Type () Type { return this.Ty }
func (this *LiteralInt) String () string { func (this *LiteralInt) String () string {
return fmt.Sprint(this.Value) return fmt.Sprint(this.Value)
} }
@ -22,11 +27,16 @@ func (this *LiteralInt) String () string {
// because it contains no inherent type information. A value cast may be used // because it contains no inherent type information. A value cast may be used
// for this purpose. // for this purpose.
type LiteralFloat struct { type LiteralFloat struct {
// Syntax
Pos lexer.Position Pos lexer.Position
Value float64 `parser:" @Float "` Value float64 `parser:" @Float "`
// Semantics
Ty Type
} }
func (*LiteralFloat) expression(){} func (*LiteralFloat) expression(){}
func (*LiteralFloat) statement(){} func (*LiteralFloat) statement(){}
func (this *LiteralFloat) Type () Type { return this.Ty }
func (this *LiteralFloat) String () string { func (this *LiteralFloat) String () string {
return fmt.Sprint(this.Value) return fmt.Sprint(this.Value)
} }
@ -39,11 +49,16 @@ func (this *LiteralFloat) String () string {
// It cannot be directly assigned to an interface because it contains no // It cannot be directly assigned to an interface because it contains no
// inherent type information. A value cast may be used for this purpose. // inherent type information. A value cast may be used for this purpose.
type LiteralArray struct { type LiteralArray struct {
// Syntax
Pos lexer.Position Pos lexer.Position
Elements []Expression `parser:" '(' '*' @@* ')' "` Elements []Expression `parser:" '(' '*' @@* ')' "`
// Semantics
Ty Type
} }
func (*LiteralArray) expression(){} func (*LiteralArray) expression(){}
func (*LiteralArray) statement(){} func (*LiteralArray) statement(){}
func (this *LiteralArray) Type () Type { return this.Ty }
func (this *LiteralArray) String () string { func (this *LiteralArray) String () string {
out := "(*" out := "(*"
for _, element := range this.Elements { for _, element := range this.Elements {
@ -60,11 +75,16 @@ func (this *LiteralArray) String () string {
// It cannot be directly assigned to an interface because it contains no // It cannot be directly assigned to an interface because it contains no
// inherent type information. A value cast may be used for this purpose. // inherent type information. A value cast may be used for this purpose.
type LiteralStruct struct { type LiteralStruct struct {
// Syntax
Pos lexer.Position Pos lexer.Position
Members []Member `parser:" '(' @@* ')' "` Members []Member `parser:" '(' @@* ')' "`
// Semantics
Ty Type
} }
func (*LiteralStruct) expression(){} func (*LiteralStruct) expression(){}
func (*LiteralStruct) statement(){} func (*LiteralStruct) statement(){}
func (this *LiteralStruct) Type () Type { return this.Ty }
func (this *LiteralStruct) String () string { func (this *LiteralStruct) String () string {
out := "(" out := "("
for index, member := range this.Members { for index, member := range this.Members {
@ -79,11 +99,16 @@ func (this *LiteralStruct) String () string {
// an interface because it contains no inherent type information. A value cast // an interface because it contains no inherent type information. A value cast
// may be used for this purpose. // may be used for this purpose.
type LiteralBoolean struct { type LiteralBoolean struct {
// Syntax
Pos lexer.Position Pos lexer.Position
Value *Boolean `parser:" @('true' | 'false') "` Value *Boolean `parser:" @('true' | 'false') "`
// Semantics
Ty Type
} }
func (*LiteralBoolean) expression(){} func (*LiteralBoolean) expression(){}
func (*LiteralBoolean) statement(){} func (*LiteralBoolean) statement(){}
func (this *LiteralBoolean) Type () Type { return this.Ty }
func (this *LiteralBoolean) String () string { func (this *LiteralBoolean) String () string {
if *this.Value { if *this.Value {
return "true" return "true"

View File

@ -38,7 +38,7 @@ func (this *Signature) Equals (ty Type) bool {
real.Name != this.Name { return false } real.Name != this.Name { return false }
for index, argument := range this.Arguments { for index, argument := range this.Arguments {
if !argument.Type.Equals(real.Arguments[index].Type) { if !argument.Type().Equals(real.Arguments[index].Type()) {
return false return false
} }
} }

View File

@ -108,7 +108,7 @@ func (this *TypeStruct) Equals (ty Type) bool {
if !ok || len(real.Members) != len(this.Members) { return false } if !ok || len(real.Members) != len(this.Members) { return false }
for index, member := range this.Members { for index, member := range this.Members {
if !member.Type.Equals(real.Members[index].Type) { if !member.Type().Equals(real.Members[index].Type()) {
return false return false
} }
} }