// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // term.go package expr import ( "strings" ) type termPriority uint32 const ( priNone termPriority = iota priRange priBut priAssign priOr priAnd priNot priRelational priSum priProduct priFraction priSelector priSign priFact priIterValue priCoalesce priIncDec priDot priValue ) type termPosition uint8 const ( posLeaf termPosition = iota posInfix posPrefix posPostfix posMultifix ) type evalFuncType func(ctx ExprContext, self *term) (v any, err error) type term struct { tk Token parent *term children []*term position termPosition // operator position: leaf, infix, prefix, postfix, multifix priority termPriority // operator priority: higher value means higher priority evalFunc evalFuncType } func (term *term) String() string { var sb strings.Builder term.toString(&sb) return sb.String() } func (term *term) toString(sb *strings.Builder) { if term.position == posLeaf { sb.WriteString(term.tk.String()) } else { sb.WriteByte('[') sb.WriteString(term.tk.String()) if term.children != nil { sb.WriteByte('(') for i, c := range term.children { if i > 0 { sb.WriteByte(' ') } c.toString(sb) } sb.WriteByte(')') } sb.WriteByte(']') } } func (term *term) getChildrenCount() (count int) { if term.position == posLeaf || term.children == nil { count = 0 } else { count = len(term.children) } return } func (term *term) getRoom() (room int) { switch term.position { case posLeaf: room = 0 case posInfix: room = 2 case posPostfix, posPrefix: room = 1 default: panic("Invalid node position") } return } func (term *term) isComplete() bool { return term.getChildrenCount() == term.getRoom() } 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] } else { panic("Can't get last child") } return } func (term *term) isLeaf() bool { return term.position == posLeaf } func (term *term) getPriority() termPriority { return term.priority } func (term *term) setParent(parent *term) { term.parent = parent if parent != nil && len(parent.children) < cap(parent.children) { parent.children = append(parent.children, term) } } func (term *term) symbol() Symbol { return term.tk.Sym } func (term *term) source() string { return term.tk.source } func (term *term) value() any { return term.tk.Value } func (term *term) compute(ctx ExprContext) (v any, err error) { if term.evalFunc == nil { err = term.tk.Errorf("undefined eval-func for %q term", term.source()) } else { v, err = term.evalFunc(ctx, term) } return } // 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 // } func (term *term) errIncompatibleTypes(leftValue, rightValue any) error { leftType := TypeName(leftValue) leftText := getFormatted(leftValue, Truncate) rightType := TypeName(rightValue) rightText := getFormatted(rightValue, Truncate) return term.tk.Errorf( "left operand '%s' [%s] and right operand '%s' [%s] are not compatible with operator %q", leftText, leftType, rightText, rightType, term.source()) } func (term *term) errIncompatibleType(value any) error { return term.tk.Errorf( "prefix/postfix operator %q do not support operand '%v' [%s]", term.source(), value, TypeName(value)) } func (term *term) Errorf(template string, args ...any) (err error) { err = term.tk.Errorf(template, args...) return } func (term *term) checkOperands() (err error) { switch term.position { case posInfix: 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()) } case posPrefix: if term.children == nil || len(term.children) != 1 || term.children[0] == nil { err = term.tk.Errorf("prefix operator %q requires one not nil operand", term.tk.String()) } case posPostfix: if term.children == nil || len(term.children) != 1 || term.anyChildrenNil() { err = term.tk.Errorf("postfix operator %q requires one not nil operand", term.tk.String()) } case posMultifix: 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()) } } return } func (term *term) anyChildrenNil() bool { for _, child := range term.children { if child == nil { return true } } return false } 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) } } return } func (term *term) evalPrefix(ctx ExprContext) (childValue any, err error) { if err = term.checkOperands(); err == nil { childValue, err = term.children[0].compute(ctx) } return } // NOTE Temporary solution to support function parameters with default value func (t *term) forceChild(c *term) { if t.children == nil { t.children = make([]*term, 0, 1) } t.children = append(t.children, c) }