Added all source files
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
// 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
|
||||
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("undfined 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
|
||||
}
|
||||
Reference in New Issue
Block a user