expr/term.go

265 lines
5.8 KiB
Go
Raw Normal View History

2024-03-26 08:45:18 +01:00
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
2024-03-26 07:00:53 +01:00
// term.go
package expr
import (
"strings"
)
type termPriority uint32
const (
priNone termPriority = iota
priRange
priBut
priAssign
priInsert
2024-03-26 07:00:53 +01:00
priOr
priAnd
priNot
priRelational
priBinOr
priBinAnd
priBinNot
2024-03-26 07:00:53 +01:00
priSum
priProduct
2024-05-01 09:47:28 +02:00
priFraction
priSelector
priBinShift
2024-03-26 07:00:53 +01:00
priSign
priFact
priIterValue
priDefault
priIncDec
priDot
2024-03-26 07:00:53 +01:00
priValue
)
type termPosition uint8
const (
posLeaf termPosition = iota
posInfix
posPrefix
posPostfix
posMultifix
2024-03-26 07:00:53 +01:00
)
type evalFuncType func(ctx ExprContext, self *term) (v any, err error)
2024-03-26 07:00:53 +01:00
type term struct {
tk Token
parent *term
children []*term
2024-04-09 05:32:50 +02:00
position termPosition // operator position: leaf, infix, prefix, postfix, multifix
2024-03-26 07:00:53 +01:00
priority termPriority // operator priority: higher value means higher priority
evalFunc evalFuncType
}
2024-07-23 15:27:50 +02:00
func (s *term) Clone() (d *term) {
var children []*term
if s.children != nil {
children = make([]*term, len(s.children))
for i, c := range s.children {
children[i] = c.Clone()
}
}
d = &term{
2024-12-23 06:53:37 +01:00
tk: *s.tk.Clone(),
parent: s.parent,
2024-07-23 15:27:50 +02:00
children: children,
position: s.position,
priority: s.priority,
evalFunc: s.evalFunc,
}
return
}
2024-07-09 07:50:50 +02:00
func (term *term) String() string {
2024-03-26 07:00:53 +01:00
var sb strings.Builder
2024-07-09 07:50:50 +02:00
term.toString(&sb)
2024-03-26 07:00:53 +01:00
return sb.String()
}
2024-07-09 07:50:50 +02:00
func (term *term) toString(sb *strings.Builder) {
if term.position == posLeaf {
sb.WriteString(term.tk.String())
2024-03-26 07:00:53 +01:00
} else {
sb.WriteByte('[')
2024-07-09 07:50:50 +02:00
sb.WriteString(term.tk.String())
if term.children != nil {
2024-03-26 07:00:53 +01:00
sb.WriteByte('(')
2024-07-09 07:50:50 +02:00
for i, c := range term.children {
2024-03-26 07:00:53 +01:00
if i > 0 {
sb.WriteByte(' ')
}
c.toString(sb)
}
sb.WriteByte(')')
}
sb.WriteByte(']')
}
}
2024-07-09 07:50:50 +02:00
func (term *term) getChildrenCount() (count int) {
if term.position == posLeaf || term.children == nil {
2024-03-26 07:00:53 +01:00
count = 0
} else {
2024-07-09 07:50:50 +02:00
count = len(term.children)
2024-03-26 07:00:53 +01:00
}
return
}
2024-07-09 07:50:50 +02:00
func (term *term) getRoom() (room int) {
switch term.position {
2024-03-26 07:00:53 +01:00
case posLeaf:
room = 0
case posInfix:
room = 2
case posPostfix, posPrefix:
room = 1
default:
panic("Invalid node position")
}
return
}
2024-07-09 07:50:50 +02:00
func (term *term) isComplete() bool {
return term.getChildrenCount() == term.getRoom()
2024-03-26 07:00:53 +01:00
}
2024-07-09 07:50:50 +02:00
func (term *term) removeLastChild() (child *term) {
if term.children != nil {
child = term.children[len(term.children)-1]
term.children = term.children[0 : len(term.children)-1]
2024-03-26 07:00:53 +01:00
} else {
panic("Can't get last child")
}
return
}
2024-07-09 07:50:50 +02:00
func (term *term) isLeaf() bool {
return term.position == posLeaf
2024-03-26 07:00:53 +01:00
}
2024-07-09 07:50:50 +02:00
func (term *term) getPriority() termPriority {
return term.priority
2024-03-26 07:00:53 +01:00
}
2024-07-09 07:50:50 +02:00
func (term *term) setParent(parent *term) {
term.parent = parent
2024-03-26 07:00:53 +01:00
if parent != nil && len(parent.children) < cap(parent.children) {
2024-07-09 07:50:50 +02:00
parent.children = append(parent.children, term)
2024-03-26 07:00:53 +01:00
}
}
2024-07-09 07:50:50 +02:00
func (term *term) symbol() Symbol {
return term.tk.Sym
}
2024-07-09 07:50:50 +02:00
func (term *term) source() string {
return term.tk.source
2024-03-26 07:00:53 +01:00
}
2024-07-09 07:50:50 +02:00
func (term *term) value() any {
return term.tk.Value
}
2024-07-09 07:50:50 +02:00
func (term *term) compute(ctx ExprContext) (v any, err error) {
if term.evalFunc == nil {
2024-07-11 06:53:14 +02:00
err = term.Errorf("undefined eval-func for %q term", term.source())
2024-03-26 07:00:53 +01:00
} else {
2024-07-09 07:50:50 +02:00
v, err = term.evalFunc(ctx, term)
2024-03-26 07:00:53 +01:00
}
return
}
2024-07-09 07:50:50 +02:00
// func (term *term) toInt(computedValue any, valueDescription string) (i int, err error) {
// if index64, ok := computedValue.(int64); ok {
// i = int(index64)
// } else {
// err = term.Errorf("%s, got %s (%v)", valueDescription, TypeName(computedValue), computedValue)
// }
// return
// }
2024-04-21 14:24:56 +02:00
2024-07-09 07:50:50 +02:00
func (term *term) errIncompatibleTypes(leftValue, rightValue any) error {
leftType := TypeName(leftValue)
leftText := getFormatted(leftValue, Truncate)
rightType := TypeName(rightValue)
rightText := getFormatted(rightValue, Truncate)
2024-07-09 07:50:50 +02:00
return term.tk.Errorf(
"left operand '%s' [%s] and right operand '%s' [%s] are not compatible with operator %q",
leftText, leftType,
rightText, rightType,
2024-07-09 07:50:50 +02:00
term.source())
2024-03-26 07:00:53 +01:00
}
2024-07-09 07:50:50 +02:00
func (term *term) errIncompatibleType(value any) error {
return term.tk.Errorf(
2024-06-05 05:48:02 +02:00
"prefix/postfix operator %q do not support operand '%v' [%s]",
2024-07-09 07:50:50 +02:00
term.source(), value, TypeName(value))
}
2024-07-09 07:50:50 +02:00
func (term *term) Errorf(template string, args ...any) (err error) {
err = term.tk.Errorf(template, args...)
return
2024-03-26 07:00:53 +01:00
}
2024-07-09 07:50:50 +02:00
func (term *term) checkOperands() (err error) {
switch term.position {
2024-03-26 07:00:53 +01:00
case posInfix:
2024-07-09 07:50:50 +02:00
if term.children == nil || len(term.children) != 2 || term.anyChildrenNil() {
err = term.tk.Errorf("infix operator %q requires two non-nil operands, got %d", term.source(), term.getChildrenCount())
2024-03-26 07:00:53 +01:00
}
case posPrefix:
2024-07-09 07:50:50 +02:00
if term.children == nil || len(term.children) != 1 || term.children[0] == nil {
2024-12-23 06:53:37 +01:00
err = term.tk.Errorf("prefix operator %q requires one non-nil operand", term.tk.String())
2024-03-26 07:00:53 +01:00
}
case posPostfix:
2024-07-09 07:50:50 +02:00
if term.children == nil || len(term.children) != 1 || term.anyChildrenNil() {
2024-12-23 06:53:37 +01:00
err = term.tk.Errorf("postfix operator %q requires one non-nil operand", term.tk.String())
}
case posMultifix:
2024-07-09 07:50:50 +02:00
if term.children == nil || len(term.children) < 3 || term.anyChildrenNil() {
err = term.tk.Errorf("infix operator %q requires at least three not operands, got %d", term.source(), term.getChildrenCount())
2024-03-26 07:00:53 +01:00
}
}
return
}
2024-07-09 07:50:50 +02:00
func (term *term) anyChildrenNil() bool {
for _, child := range term.children {
if child == nil {
return true
}
}
return false
}
2024-07-09 07:50:50 +02:00
func (term *term) evalInfix(ctx ExprContext) (leftValue, rightValue any, err error) {
if err = term.checkOperands(); err == nil {
if leftValue, err = term.children[0].compute(ctx); err == nil {
rightValue, err = term.children[1].compute(ctx)
2024-03-26 07:00:53 +01:00
}
}
return
}
2024-07-09 07:50:50 +02:00
func (term *term) evalPrefix(ctx ExprContext) (childValue any, err error) {
if err = term.checkOperands(); err == nil {
childValue, err = term.children[0].compute(ctx)
2024-03-26 07:00:53 +01:00
}
return
}
// NOTE Temporary solution to support function parameters with default value
2024-07-09 07:50:50 +02:00
func (t *term) forceChild(c *term) {
if t.children == nil {
t.children = make([]*term, 0, 1)
}
2024-07-09 07:50:50 +02:00
t.children = append(t.children, c)
}