expr/term.go

235 lines
4.8 KiB
Go

// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// term.go
package expr
import (
"fmt"
"strings"
)
type termKind uint16
const (
kindUnknown termKind = iota
kindBool
kindInteger
kindFloat
kindString
kindIdentifier
)
type termClass uint16
const (
classNull termClass = iota
classConst
classVar
classFunc
classOperator
)
type termPriority uint32
const (
priNone termPriority = iota
priBut
priAssign
priOr
priAnd
priNot
priRelational
priSum
priProduct
priSign
priFact
priValue
)
type termPosition uint8
const (
posLeaf termPosition = iota
posInfix
posPrefix
posPostfix
)
type evalFuncType func(ctx exprContext, self *term) (v any, err error)
// type iterm interface {
// getClass() termClass
// getKind() termKind
// compute(ctx exprContext) (v any, err error)
// // isOperator() bool
// // isOperand() bool
// source() string
// setParent(parentNode term)
// }
type term struct {
tk Token
class termClass
kind termKind
parent *term
children []*term
position termPosition // operator position: infix, prefix, suffix
priority termPriority // operator priority: higher value means higher priority
evalFunc evalFuncType
}
func (self *term) String() string {
var sb strings.Builder
self.toString(&sb)
return sb.String()
}
func (self *term) toString(sb *strings.Builder) {
if self.position == posLeaf {
sb.WriteString(self.tk.String())
} else {
sb.WriteByte('[')
sb.WriteString(self.tk.String())
if self.children != nil {
sb.WriteByte('(')
for i, c := range self.children {
if i > 0 {
sb.WriteByte(' ')
}
c.toString(sb)
}
sb.WriteByte(')')
}
sb.WriteByte(']')
}
}
func (self *term) getChildrenCount() (count int) {
if self.position == posLeaf || self.children == nil {
count = 0
} else {
count = len(self.children)
}
return
}
func (self *term) getRoom() (room int) {
switch self.position {
case posLeaf:
room = 0
case posInfix:
room = 2
case posPostfix, posPrefix:
room = 1
default:
panic("Invalid node position")
}
return
}
func (self *term) isComplete() bool {
return self.getChildrenCount() == self.getRoom()
}
func (self *term) removeLastChild() (child *term) {
if self.children != nil {
child = self.children[len(self.children)-1]
self.children = self.children[0 : len(self.children)-1]
} else {
panic("Can't get last child")
}
return
}
func (self *term) isLeaf() bool {
return self.position == posLeaf
}
// func (self *term) getKind() termKind {
// return self.kind
// }
// func (self *term) getClass() termClass {
// return self.class
// }
func (self *term) getPriority() termPriority {
return self.priority
}
func (self *term) setParent(parent *term) {
self.parent = parent
if parent != nil && len(parent.children) < cap(parent.children) {
parent.children = append(parent.children, self)
}
}
// func (self *term) isOperand() bool {
// return self.getClass() != classOperator
// }
// func (self *term) isOperator() bool {
// return self.getClass() == classOperator
// }
func (self *term) source() string {
return self.tk.source
}
func (self *term) compute(ctx exprContext) (v any, err error) {
if self.evalFunc == nil {
err = fmt.Errorf("undefined eval-func for %v term type", self.kind)
} else {
v, err = self.evalFunc(ctx, self)
}
return
}
func (self *term) errIncompatibleTypes(leftValue, rightValue any) error {
return fmt.Errorf(
"left operand '%v' [%T] is not compatible with right operand '%v' [%T] with respect to operator %q",
leftValue, leftValue,
rightValue, rightValue,
self.source())
}
func (self *term) errIncompatibleType(value any) error {
return fmt.Errorf(
"prefix/postfix operator %q do not support operand '%v' [%T]", self.source(), value, value)
}
func (self *term) checkOperands() (err error) {
switch self.position {
case posInfix:
if self.children == nil || len(self.children) != 2 || self.children[0] == nil || self.children[1] == nil {
err = fmt.Errorf("infix operator %q requires two operands, got %d", self.source(), self.getChildrenCount())
}
case posPrefix:
if self.children == nil || len(self.children) != 1 || self.children[0] == nil {
err = fmt.Errorf("prefix operator %q requires one operand", self.tk.String())
}
case posPostfix:
if self.children == nil || len(self.children) != 1 || self.children[0] == nil {
err = fmt.Errorf("postfix operator %q requires one operand", self.tk.String())
}
}
return
}
func (self *term) evalInfix(ctx exprContext) (leftValue, rightValue any, err error) {
if err = self.checkOperands(); err == nil {
if leftValue, err = self.children[0].compute(ctx); err == nil {
rightValue, err = self.children[1].compute(ctx)
}
}
return
}
func (self *term) evalPrefix(ctx exprContext) (rightValue any, err error) {
if err = self.checkOperands(); err == nil {
rightValue, err = self.children[0].compute(ctx)
}
return
}