fspl/analyzer/expression.go

97 lines
2.5 KiB
Go

package analyzer
// import "fmt"
import "github.com/alecthomas/participle/v2"
import "git.tebibyte.media/sashakoshka/fspl/entity"
// TODO all expression analysis routines must take in the type they are being
// assigned to and return an error if they can't be assigned to it. if the type
// is nil, the expression must ignore it unless it can do upwards type
// inference. need to also figure out comparison operators
func (this *Tree) analyzeVariable (
into entity.Type,
variable *entity.Variable,
) (
entity.Expression,
error,
) {
declaration := this.Variable(variable.Name)
if declaration == nil {
return nil, participle.Errorf (
variable.Pos, "no variable named %s",
variable.Name)
}
err := this.canAssignStrict(variable.Pos, into, declaration.Type)
if err != nil { return nil, err }
variable.Declaration = declaration
return variable, nil
}
func (this *Tree) analyzeDeclaration (
into entity.Type,
declaration *entity.Declaration,
) (
entity.Expression,
error,
) {
existing := this.TopScope().Variable(declaration.Name)
if existing != nil {
return nil, participle.Errorf (
declaration.Pos,
"%s already declared in block at %v",
declaration.Name, existing.Pos)
}
ty, err := this.analyzeType(declaration.Type, false)
declaration.Type = ty
if err != nil { return nil, err }
err = this.canAssignStrict(declaration.Pos, into, declaration.Type)
if err != nil { return nil, err }
this.AddVariable(declaration)
return &entity.Variable {
Pos: declaration.Pos,
Name: declaration.Name,
Declaration: declaration,
}, nil
}
func (this *Tree) analyzeCall (
into entity.Type,
call *entity.Call,
) (
entity.Expression,
error,
) {
function, err := this.analyzeFunction(call.Pos, call.Name)
call.Function = function
if err != nil { return nil, err }
err = this.canAssignStrict(call.Pos, into, function.Signature.Return)
if err != nil { return nil, err }
if len(call.Arguments) > len(function.Signature.Arguments) {
return nil, participle.Errorf (
call.Pos, "too many arguments in call to %s",
call.Name)
} else if len(call.Arguments) < len(function.Signature.Arguments) {
return nil, participle.Errorf (
call.Pos, "too few arguments in call to %s",
call.Name)
}
for index, argument := range call.Arguments {
signature := function.Signature
correct := signature.ArgumentMap[signature.ArgumentOrder[index]]
argument, err := this.analyzeExpression(correct.Type, argument)
if err != nil { return nil, err }
call.Arguments[index] = argument
}
return call, nil
}