moved scanner sources to package 'scan'
This commit is contained in:
+301
@@ -0,0 +1,301 @@
|
||||
// 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)
|
||||
}
|
||||
Reference in New Issue
Block a user