// 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 }