Added stub for constant expression evaluator

This commit is contained in:
Sasha Koshka 2024-04-12 00:43:24 -04:00
parent 034d9661b3
commit 373db2ae81
2 changed files with 108 additions and 0 deletions

2
eval/doc.go Normal file
View File

@ -0,0 +1,2 @@
// Package eval provides a way to evaluate FSPL expressions.
package eval

106
eval/eval.go Normal file
View File

@ -0,0 +1,106 @@
package eval
import "git.tebibyte.media/fspl/fspl/errors"
import "git.tebibyte.media/fspl/fspl/entity"
type evaluator struct { }
func (this *evaluator) assertConstant (expression entity.Expression) error {
if expression.IsConstant() {
return nil
} else {
return errors.Errorf(expression.Position(), "%v is not constant", expression)
}
}
// EvaluateConstant evaluates a constant expression. On success, it always
// returns a literal made of other literals. It is very important that the input
// expression has come from the semantic analyzer.
func EvaluateConstant (expression entity.Expression) (entity.Expression, error) {
// evaluate
this := new(evaluator)
expression, err := this.evaluateConstant(expression)
if err != nil { return nil, err }
// sanity check
if !expression.IsConstant() {
panic("BUG: evaluation result is not constant")
}
return expression, nil
}
func (this *evaluator) evaluateConstant (expression entity.Expression) (entity.Expression, error) {
// TODO expand this to include all constant expressions
switch expression := expression.(type) {
case *entity.LiteralInt:
return expression, nil
case *entity.LiteralFloat:
return expression, nil
case *entity.LiteralString:
return expression, nil
case *entity.LiteralArray:
return this.evaluateConstantLiteralArray(expression)
case *entity.LiteralStruct:
return this.evaluateConstantLiteralStruct(expression)
case *entity.LiteralBoolean:
return expression, nil
case *entity.LiteralNil:
return expression, nil
case *entity.Constant:
return expression.Declaration.Value, nil
default:
err := this.assertConstant(expression)
if err != nil { return nil, err }
return nil, errors.Errorf (
expression.Position(),
"%v expressions are currently unsupported by the " +
"constant expression evaluator")
}
}
func (this *evaluator) evaluateConstantLiteralArray (array *entity.LiteralArray) (entity.Expression, error) {
result := &entity.LiteralArray {
Pos: array.Position(),
Elements: make([]entity.Expression, len(array.Elements)),
Ty: array.Type(),
}
for index, element := range array.Elements {
elementResult, err := this.evaluateConstant(element)
if err != nil { return nil, err }
result.Elements[index] = elementResult
}
return result, nil
}
func (this *evaluator) evaluateConstantLiteralStruct (struc *entity.LiteralStruct) (entity.Expression, error) {
result := &entity.LiteralStruct {
Pos: struc.Position(),
Members: make([]*entity.Member, len(struc.Members)),
MemberOrder: make([]string, len(struc.MemberOrder)),
MemberMap: make(map[string] *entity.Member),
Ty: struc.Type(),
}
for index, member := range struc.Members {
memberResult := &entity.Member {
Pos: member.Position(),
Name: member.Name,
}
memberValueResult, err := this.evaluateConstant(member.Value)
if err != nil { return nil, err }
memberResult.Value = memberValueResult
result.Members[index] = memberResult
result.MemberOrder[index] = memberResult.Name
result.MemberMap[memberResult.Name] = memberResult
}
return result, nil
}