97 lines
2.5 KiB
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
|
|
}
|