// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // term.go package scan import ( "strings" "git.portale-stac.it/go-pkg/expr/kern" ) type TermPriority uint32 const ( PriNone TermPriority = iota PriRange PriIterOp // map, filter, digest, etc PriBut PriAssign PriInsert PriOr PriAnd PriNot PriRelational PriBitwiseOr PriBitwiseAnd PriBitwiseNot PriSum PriProduct PriFraction PriSelector PriBinShift PriSign PriFact PriIterValue PriDefault PriIncDec PriDot PriDereference PriValue PriBitwiseXor = PriBitwiseOr ) type TermPosition uint8 const ( PosLeaf TermPosition = iota PosInfix PosPrefix PosPostfix PosMultifix ) type EvalFuncType func(ctx kern.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 (t *Term) Clone() (d *Term) { var children []*Term if t.Children != nil { children = make([]*Term, len(t.Children)) for i, c := range t.Children { children[i] = c.Clone() } } d = &Term{ Tk: *t.Tk.Clone(), Parent: t.Parent, Children: children, Position: t.Position, Priority: t.Priority, EvalFunc: t.EvalFunc, } return } func (t *Term) String() string { var sb strings.Builder t.ToString(&sb) return sb.String() } func (t *Term) ToString(sb *strings.Builder) { if t.Position == PosLeaf { sb.WriteString(t.Tk.String()) } else { sb.WriteByte('[') sb.WriteString(t.Tk.String()) if t.Children != nil { sb.WriteByte('(') for i, c := range t.Children { if i > 0 { sb.WriteByte(' ') } c.ToString(sb) } sb.WriteByte(')') } sb.WriteByte(']') } } func (t *Term) GetChildCount() (count int) { if t.Position == PosLeaf || t.Children == nil { count = 0 } else { count = len(t.Children) } return } func (t *Term) GetRoom() (room int) { switch t.Position { case PosLeaf: room = 0 case PosInfix: room = 2 case PosPostfix, PosPrefix: room = 1 default: panic("Invalid node position") } return } func (t *Term) isComplete() bool { return t.GetChildCount() == t.GetRoom() } func (t *Term) removeLastChild() (child *Term) { if t.Children != nil { child = t.Children[len(t.Children)-1] t.Children = t.Children[0 : len(t.Children)-1] } else { panic("Can't get last child") } return } func (t *Term) isLeaf() bool { return t.Position == PosLeaf } func (t *Term) getPriority() TermPriority { return t.Priority } func (t *Term) SetParent(parent *Term) { t.Parent = parent if parent != nil && len(parent.Children) < cap(parent.Children) { parent.Children = append(parent.Children, t) } } func (t *Term) Symbol() Symbol { return t.Tk.Sym } func (t *Term) Source() string { return t.Tk.source } func (t *Term) Value() any { return t.Tk.Value } func (t *Term) GetChild(index int) (c kern.Term) { if index >= 0 && index < len(t.Children) { c = t.Children[index] } return } func (t *Term) GetChildSource(index int) (s string) { if index >= 0 && index < len(t.Children) { s = t.Children[index].Tk.source } return } func (t *Term) IsAssign() bool { return t.Symbol() == SymEqual } func (t *Term) Compute(ctx kern.ExprContext) (v any, err error) { if t.EvalFunc == nil { err = t.Errorf("undefined eval-func for %q term", t.Source()) } else { v, err = t.EvalFunc(ctx, t) } 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 (t *Term) ErrIncompatibleTypes(leftValue, rightValue any) error { leftType := kern.TypeName(leftValue) leftText := kern.GetFormatted(leftValue, kern.Truncate) rightType := kern.TypeName(rightValue) rightText := kern.GetFormatted(rightValue, kern.Truncate) return t.Tk.Errorf( "left operand '%s' [%s] and right operand '%s' [%s] are not compatible with operator %q", leftText, leftType, rightText, rightType, t.Source()) } func (t *Term) ErrIncompatibleType(value any, side string) error { return t.Tk.Errorf( "operator %q does not support operand '%v' [%s] on its %s side", t.Source(), value, kern.TypeName(value), side) } func (t *Term) ErrIncompatiblePrefixPostfixType(value any) error { return t.Tk.Errorf( "prefix/postfix operator %q does not support operand '%v' [%s]", t.Source(), value, kern.TypeName(value)) } func (t *Term) ErrDivisionByZero() error { return t.Tk.Errorf("division by zero") } func (t *Term) ErrKeyNotFound(key any) error { return t.Tk.Errorf("key '%v' not found", key) } func (t *Term) Errorf(template string, args ...any) (err error) { err = t.Tk.Errorf(template, args...) return } func (t *Term) CheckOperands() (err error) { switch t.Position { case PosInfix: if t.Children == nil || len(t.Children) != 2 || t.anyChildrenNil() { err = t.Tk.Errorf("infix operator %q requires two non-nil operands, got %d", t.Source(), t.GetChildCount()) } case PosPrefix: if t.Children == nil || len(t.Children) != 1 || t.Children[0] == nil { err = t.Tk.Errorf("prefix operator %q requires one non-nil operand", t.Tk.String()) } case PosPostfix: if t.Children == nil || len(t.Children) != 1 || t.anyChildrenNil() { err = t.Tk.Errorf("postfix operator %q requires one non-nil operand", t.Tk.String()) } case PosMultifix: if len(t.Children) < 3 || t.anyChildrenNil() { err = t.Tk.Errorf("infix operator %q requires at least three not operands, got %d", t.Source(), t.GetChildCount()) } } return } func (t *Term) anyChildrenNil() bool { for _, child := range t.Children { if child == nil { return true } } return false } func (t *Term) EvalInfix(ctx kern.ExprContext) (leftValue, rightValue any, err error) { if err = t.CheckOperands(); err == nil { if leftValue, err = t.Children[0].Compute(ctx); err == nil { rightValue, err = t.Children[1].Compute(ctx) } } return } func (t *Term) EvalPrefix(ctx kern.ExprContext) (childValue any, err error) { if err = t.CheckOperands(); err == nil { childValue, err = t.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) }