Compare commits
	
		
			21 Commits
		
	
	
		
			f51d6023ae
			...
			8144122d2c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8144122d2c | |||
| 188ea354ee | |||
| 2fc6bbfe10 | |||
| 847d85605e | |||
| 9c29392389 | |||
| a7b6e6f8d2 | |||
| a16ac70e4a | |||
| ab2e3f0528 | |||
| 974835a8ef | |||
| 457a656073 | |||
| 9e63e1402e | |||
| e4ded4f746 | |||
| 4e3af837e6 | |||
| ca12722c93 | |||
| d96123ab02 | |||
| f2d6d63017 | |||
| 905b2af7fa | |||
| 9307473d08 | |||
| 10a596a4cd | |||
| 609fb21505 | |||
| 7650a4a441 | 
@ -25,15 +25,11 @@ func errTooMuchParams(funcName string, maxArgs, argCount int) (err error) {
 | 
				
			|||||||
// --- General errors
 | 
					// --- General errors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func errCantConvert(funcName string, value any, kind string) error {
 | 
					func errCantConvert(funcName string, value any, kind string) error {
 | 
				
			||||||
	if typer, ok := value.(Typer); ok {
 | 
						return fmt.Errorf("%s(): can't convert %s to %s", funcName, typeName(value), kind)
 | 
				
			||||||
		return fmt.Errorf("%s(): can't convert %s to %s", funcName, typer.TypeName(), kind)
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return fmt.Errorf("%s(): can't convert %T to %s", funcName, value, kind)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func errExpectedGot(funcName string, kind string, value any) error {
 | 
					func errExpectedGot(funcName string, kind string, value any) error {
 | 
				
			||||||
	return fmt.Errorf("%s() expected %s, got %T (%v)", funcName, kind, value, value)
 | 
						return fmt.Errorf("%s() expected %s, got %s (%v)", funcName, kind, typeName(value), value)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func errFuncDivisionByZero(funcName string) error {
 | 
					func errFuncDivisionByZero(funcName string) error {
 | 
				
			||||||
@ -46,18 +42,14 @@ func errDivisionByZero() error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// --- Parameter errors
 | 
					// --- Parameter errors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// func errOneParam(funcName string) error {
 | 
					 | 
				
			||||||
// 	return fmt.Errorf("%s() requires exactly one param", funcName)
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func errMissingRequiredParameter(funcName, paramName string) error {
 | 
					func errMissingRequiredParameter(funcName, paramName string) error {
 | 
				
			||||||
	return fmt.Errorf("%s() missing required parameter %q", funcName, paramName)
 | 
						return fmt.Errorf("%s() missing required parameter %q", funcName, paramName)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func errInvalidParameterValue(funcName, paramName string, paramValue any) error {
 | 
					func errInvalidParameterValue(funcName, paramName string, paramValue any) error {
 | 
				
			||||||
	return fmt.Errorf("%s() invalid value %T (%v) for parameter %q", funcName, paramValue, paramValue, paramName)
 | 
						return fmt.Errorf("%s() invalid value %s (%v) for parameter %q", funcName, typeName(paramValue), paramValue, paramName)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func errWrongParamType(funcName, paramName, paramType string, paramValue any) error {
 | 
					func errWrongParamType(funcName, paramName, paramType string, paramValue any) error {
 | 
				
			||||||
	return fmt.Errorf("%s() the %q parameter must be a %s, got a %T (%v)", funcName, paramName, paramType, paramValue, paramValue)
 | 
						return fmt.Errorf("%s() the %q parameter must be a %s, got a %s (%v)", funcName, paramName, paramType, typeName(paramValue), paramValue)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										130
									
								
								dict-type.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								dict-type.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// dict-type.go
 | 
				
			||||||
 | 
					package expr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DictType map[any]any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newDict(dictAny map[any]*term) (dict *DictType) {
 | 
				
			||||||
 | 
						var d DictType
 | 
				
			||||||
 | 
						if dictAny != nil {
 | 
				
			||||||
 | 
							d = make(DictType, len(dictAny))
 | 
				
			||||||
 | 
							for i, item := range dictAny {
 | 
				
			||||||
 | 
								d[i] = item
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							d = make(DictType)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dict = &d
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dict *DictType) toMultiLine(sb *strings.Builder, indent int) {
 | 
				
			||||||
 | 
						sb.WriteString(strings.Repeat("\t", indent))
 | 
				
			||||||
 | 
						sb.WriteString("{\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						first := true
 | 
				
			||||||
 | 
						for name, value := range *dict {
 | 
				
			||||||
 | 
							if first {
 | 
				
			||||||
 | 
								first = false
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								sb.WriteByte(',')
 | 
				
			||||||
 | 
								sb.WriteByte('\n')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sb.WriteString(strings.Repeat("\t", indent+1))
 | 
				
			||||||
 | 
							if key, ok := name.(string); ok {
 | 
				
			||||||
 | 
								sb.WriteString(string('"') + key + string('"'))
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								sb.WriteString(fmt.Sprintf("%v", name))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sb.WriteString(": ")
 | 
				
			||||||
 | 
							if f, ok := value.(Formatter); ok {
 | 
				
			||||||
 | 
								sb.WriteString(f.ToString(MultiLine))
 | 
				
			||||||
 | 
							} else if _, ok = value.(Functor); ok {
 | 
				
			||||||
 | 
								sb.WriteString("func(){}")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								sb.WriteString(fmt.Sprintf("%v", value))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sb.WriteString(strings.Repeat("\t", indent))
 | 
				
			||||||
 | 
						sb.WriteString("\n}")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dict *DictType) ToString(opt FmtOpt) string {
 | 
				
			||||||
 | 
						var sb strings.Builder
 | 
				
			||||||
 | 
						if opt&MultiLine != 0 {
 | 
				
			||||||
 | 
							dict.toMultiLine(&sb, 0)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							sb.WriteByte('{')
 | 
				
			||||||
 | 
							first := true
 | 
				
			||||||
 | 
							for key, value := range *dict {
 | 
				
			||||||
 | 
								if first {
 | 
				
			||||||
 | 
									first = false
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									sb.WriteString(", ")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if s, ok := key.(string); ok {
 | 
				
			||||||
 | 
									sb.WriteString(string('"') + s + string('"'))
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									sb.WriteString(fmt.Sprintf("%v", key))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								sb.WriteString(": ")
 | 
				
			||||||
 | 
								if formatter, ok := value.(Formatter); ok {
 | 
				
			||||||
 | 
									sb.WriteString(formatter.ToString(opt))
 | 
				
			||||||
 | 
								} else if t, ok := value.(*term); ok {
 | 
				
			||||||
 | 
									sb.WriteString(t.String())
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									sb.WriteString(fmt.Sprintf("%#v", value))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sb.WriteByte('}')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sb.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dict *DictType) String() string {
 | 
				
			||||||
 | 
						return dict.ToString(0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dict *DictType) TypeName() string {
 | 
				
			||||||
 | 
						return "dict"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dict *DictType) hasKey(target any) (ok bool) {
 | 
				
			||||||
 | 
						for key := range *dict {
 | 
				
			||||||
 | 
							if ok = reflect.DeepEqual(key, target); ok {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dict *DictType) clone() (c *DictType) {
 | 
				
			||||||
 | 
						c = newDict(nil)
 | 
				
			||||||
 | 
						for k, v := range *dict {
 | 
				
			||||||
 | 
							(*c)[k] = v
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dict *DictType) merge(second *DictType) {
 | 
				
			||||||
 | 
						if second != nil {
 | 
				
			||||||
 | 
							for k, v := range *second {
 | 
				
			||||||
 | 
								(*dict)[k] = v
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dict *DictType) setItem(key any, value any) (err error) {
 | 
				
			||||||
 | 
						(*dict)[key]=value
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -51,8 +51,10 @@ type Typer interface {
 | 
				
			|||||||
	TypeName() string
 | 
						TypeName() string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getTypeName(v any) (name string) {
 | 
					func typeName(v any) (name string) {
 | 
				
			||||||
	if typer, ok := v.(Typer); ok {
 | 
						if v == nil {
 | 
				
			||||||
 | 
							name = "nil"
 | 
				
			||||||
 | 
						} else if typer, ok := v.(Typer); ok {
 | 
				
			||||||
		name = typer.TypeName()
 | 
							name = typer.TypeName()
 | 
				
			||||||
	} else if IsInteger(v) {
 | 
						} else if IsInteger(v) {
 | 
				
			||||||
		name = "integer"
 | 
							name = "integer"
 | 
				
			||||||
 | 
				
			|||||||
@ -33,52 +33,10 @@ func float64ToFraction(f float64) (fract *FractionType, err error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	dec := fmt.Sprintf("%.12f", decPart)
 | 
						dec := fmt.Sprintf("%.12f", decPart)
 | 
				
			||||||
	s := fmt.Sprintf("%s%.f%s", sign, intPart, dec[1:])
 | 
						s := fmt.Sprintf("%s%.f%s", sign, intPart, dec[1:])
 | 
				
			||||||
	// fmt.Printf("S: '%s'\n",s)
 | 
					 | 
				
			||||||
	return makeGeneratingFraction(s)
 | 
						return makeGeneratingFraction(s)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Based on https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/math/big/rat.go;l=39
 | 
					// Based on https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/math/big/rat.go;l=39
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
func _float64ToFraction(f float64) (num, den int64, err error) {
 | 
					 | 
				
			||||||
	const expMask = 1<<11 - 1
 | 
					 | 
				
			||||||
	bits := math.Float64bits(f)
 | 
					 | 
				
			||||||
	mantissa := bits & (1<<52 - 1)
 | 
					 | 
				
			||||||
	exp := int((bits >> 52) & expMask)
 | 
					 | 
				
			||||||
	switch exp {
 | 
					 | 
				
			||||||
	case expMask: // non-finite
 | 
					 | 
				
			||||||
		err = errors.New("infite")
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	case 0: // denormal
 | 
					 | 
				
			||||||
		exp -= 1022
 | 
					 | 
				
			||||||
	default: // normal
 | 
					 | 
				
			||||||
		mantissa |= 1 << 52
 | 
					 | 
				
			||||||
		exp -= 1023
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	shift := 52 - exp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Optimization (?): partially pre-normalise.
 | 
					 | 
				
			||||||
	for mantissa&1 == 0 && shift > 0 {
 | 
					 | 
				
			||||||
		mantissa >>= 1
 | 
					 | 
				
			||||||
		shift--
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if f < 0 {
 | 
					 | 
				
			||||||
		num = -int64(mantissa)
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		num = int64(mantissa)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	den = int64(1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if shift > 0 {
 | 
					 | 
				
			||||||
		den = den << shift
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		num = num << (-shift)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func makeGeneratingFraction(s string) (f *FractionType, err error) {
 | 
					func makeGeneratingFraction(s string) (f *FractionType, err error) {
 | 
				
			||||||
	var num, den int64
 | 
						var num, den int64
 | 
				
			||||||
	var sign int64 = 1
 | 
						var sign int64 = 1
 | 
				
			||||||
 | 
				
			|||||||
@ -40,11 +40,25 @@ func GetVar(ctx ExprContext, name string) (value any, exists bool) {
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetLocalFuncInfo(ctx ExprContext, name string) (item ExprFunc, exists bool) {
 | 
				
			||||||
 | 
						var v any
 | 
				
			||||||
 | 
						if len(name) > 0 {
 | 
				
			||||||
 | 
							if v, exists = ctx.GetVar(name); exists && isFunctor(v) {
 | 
				
			||||||
 | 
								f, _ := v.(Functor)
 | 
				
			||||||
 | 
								item = f.GetFunc()
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								item, exists = ctx.GetFuncInfo(name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
func GetFuncInfo(ctx ExprContext, name string) (item ExprFunc, exists bool, ownerCtx ExprContext) {
 | 
					func GetFuncInfo(ctx ExprContext, name string) (item ExprFunc, exists bool, ownerCtx ExprContext) {
 | 
				
			||||||
	if item, exists = ctx.GetFuncInfo(name); exists {
 | 
						if len(name) > 0 {
 | 
				
			||||||
		ownerCtx = ctx
 | 
							if item, exists = GetLocalFuncInfo(ctx, name); exists {
 | 
				
			||||||
	} else if item, exists = globalCtx.GetFuncInfo(name); exists {
 | 
								ownerCtx = ctx
 | 
				
			||||||
		ownerCtx = globalCtx
 | 
							} else if item, exists = globalCtx.GetFuncInfo(name); exists {
 | 
				
			||||||
 | 
								ownerCtx = globalCtx
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										15
									
								
								iter-list.go
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								iter-list.go
									
									
									
									
									
								
							@ -106,10 +106,19 @@ func (it *ListIterator) CallOperation(name string, args []any) (v any, err error
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (it *ListIterator) Current() (item any, err error) {
 | 
					func (it *ListIterator) Current() (item any, err error) {
 | 
				
			||||||
	a := *(it.a)
 | 
						a := *(it.a)
 | 
				
			||||||
	if it.index >= 0 && it.index <= it.stop {
 | 
						if it.start <= it.stop {
 | 
				
			||||||
		item = a[it.index]
 | 
							if it.stop < len(a) && it.index >= it.start && it.index <= it.stop {
 | 
				
			||||||
 | 
								item = a[it.index]
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								err = io.EOF
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		err = io.EOF
 | 
							if it.start < len(a) && it.index >= it.stop && it.index <= it.start {
 | 
				
			||||||
 | 
								item = a[it.index]
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								err = io.EOF
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,7 @@ type ExtIterator interface {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func errNoOperation(name string) error {
 | 
					func errNoOperation(name string) error {
 | 
				
			||||||
	return fmt.Errorf("no %q function defined in the data-source", name)
 | 
						return fmt.Errorf("no %s() function defined in the data-source", name)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func errInvalidDataSource() error {
 | 
					func errInvalidDataSource() error {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								list-type.go
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								list-type.go
									
									
									
									
									
								
							@ -13,6 +13,9 @@ import (
 | 
				
			|||||||
type ListType []any
 | 
					type ListType []any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newListA(listAny ...any) (list *ListType) {
 | 
					func newListA(listAny ...any) (list *ListType) {
 | 
				
			||||||
 | 
						if listAny == nil {
 | 
				
			||||||
 | 
							listAny = []any{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return newList(listAny)
 | 
						return newList(listAny)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -147,3 +150,13 @@ func deepSame(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (list *ListType) setItem(index int64, value any) (err error) {
 | 
				
			||||||
 | 
						if index >= 0 && index < int64(len(*list)) {
 | 
				
			||||||
 | 
							(*list)[index] = value
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							err = fmt.Errorf("index %d out of bounds (0, %d)", index, len(*list)-1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										118
									
								
								operand-dict.go
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								operand-dict.go
									
									
									
									
									
								
							@ -4,124 +4,6 @@
 | 
				
			|||||||
// operand-dict.go
 | 
					// operand-dict.go
 | 
				
			||||||
package expr
 | 
					package expr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"reflect"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type DictType map[any]any
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newDict(dictAny map[any]*term) (dict *DictType) {
 | 
					 | 
				
			||||||
	var d DictType
 | 
					 | 
				
			||||||
	if dictAny != nil {
 | 
					 | 
				
			||||||
		d = make(DictType, len(dictAny))
 | 
					 | 
				
			||||||
		for i, item := range dictAny {
 | 
					 | 
				
			||||||
			d[i] = item
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		d = make(DictType)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	dict = &d
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (dict *DictType) toMultiLine(sb *strings.Builder, indent int) {
 | 
					 | 
				
			||||||
	sb.WriteString(strings.Repeat("\t", indent))
 | 
					 | 
				
			||||||
	sb.WriteString("{\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	first := true
 | 
					 | 
				
			||||||
	for name, value := range *dict {
 | 
					 | 
				
			||||||
		if first {
 | 
					 | 
				
			||||||
			first = false
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			sb.WriteByte(',')
 | 
					 | 
				
			||||||
			sb.WriteByte('\n')
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		sb.WriteString(strings.Repeat("\t", indent+1))
 | 
					 | 
				
			||||||
		if key, ok := name.(string); ok {
 | 
					 | 
				
			||||||
			sb.WriteString(string('"') + key + string('"'))
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			sb.WriteString(fmt.Sprintf("%v", name))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sb.WriteString(": ")
 | 
					 | 
				
			||||||
		if f, ok := value.(Formatter); ok {
 | 
					 | 
				
			||||||
			sb.WriteString(f.ToString(MultiLine))
 | 
					 | 
				
			||||||
		} else if _, ok = value.(Functor); ok {
 | 
					 | 
				
			||||||
			sb.WriteString("func(){}")
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			sb.WriteString(fmt.Sprintf("%v", value))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sb.WriteString(strings.Repeat("\t", indent))
 | 
					 | 
				
			||||||
	sb.WriteString("\n}")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (dict *DictType) ToString(opt FmtOpt) string {
 | 
					 | 
				
			||||||
	var sb strings.Builder
 | 
					 | 
				
			||||||
	if opt&MultiLine != 0 {
 | 
					 | 
				
			||||||
		dict.toMultiLine(&sb, 0)
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		sb.WriteByte('{')
 | 
					 | 
				
			||||||
		first := true
 | 
					 | 
				
			||||||
		for key, value := range *dict {
 | 
					 | 
				
			||||||
			if first {
 | 
					 | 
				
			||||||
				first = false
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				sb.WriteString(", ")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if s, ok := key.(string); ok {
 | 
					 | 
				
			||||||
				sb.WriteString(string('"') + s + string('"'))
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				sb.WriteString(fmt.Sprintf("%v", key))
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			sb.WriteString(": ")
 | 
					 | 
				
			||||||
			if formatter, ok := value.(Formatter); ok {
 | 
					 | 
				
			||||||
				sb.WriteString(formatter.ToString(opt))
 | 
					 | 
				
			||||||
			} else if t, ok := value.(*term); ok {
 | 
					 | 
				
			||||||
				sb.WriteString(t.String())
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				sb.WriteString(fmt.Sprintf("%#v", value))
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sb.WriteByte('}')
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return sb.String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (dict *DictType) String() string {
 | 
					 | 
				
			||||||
	return dict.ToString(0)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (dict *DictType) TypeName() string {
 | 
					 | 
				
			||||||
	return "dict"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (dict *DictType) hasKey(target any) (ok bool) {
 | 
					 | 
				
			||||||
	for key := range *dict {
 | 
					 | 
				
			||||||
		if ok = reflect.DeepEqual(key, target); ok {
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (dict *DictType) clone() (c *DictType) {
 | 
					 | 
				
			||||||
	c = newDict(nil)
 | 
					 | 
				
			||||||
	for k, v := range *dict {
 | 
					 | 
				
			||||||
		(*c)[k] = v
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (dict *DictType) merge(second *DictType) {
 | 
					 | 
				
			||||||
	if second != nil {
 | 
					 | 
				
			||||||
		for k, v := range *second {
 | 
					 | 
				
			||||||
			(*dict)[k] = v
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// -------- dict term
 | 
					// -------- dict term
 | 
				
			||||||
func newDictTerm(args map[any]*term) *term {
 | 
					func newDictTerm(args map[any]*term) *term {
 | 
				
			||||||
 | 
				
			|||||||
@ -40,7 +40,6 @@ func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err erro
 | 
				
			|||||||
			err = errTooMuchParams(name, info.MaxArgs(), len(*varParams))
 | 
								err = errTooMuchParams(name, info.MaxArgs(), len(*varParams))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err == nil && owner != ctx {
 | 
							if err == nil && owner != ctx {
 | 
				
			||||||
			// ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
 | 
					 | 
				
			||||||
			ctx.RegisterFuncInfo(info)
 | 
								ctx.RegisterFuncInfo(info)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@ -52,7 +51,6 @@ func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err erro
 | 
				
			|||||||
func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) {
 | 
					func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) {
 | 
				
			||||||
	ctx := cloneContext(parentCtx)
 | 
						ctx := cloneContext(parentCtx)
 | 
				
			||||||
	name, _ := self.tk.Value.(string)
 | 
						name, _ := self.tk.Value.(string)
 | 
				
			||||||
	// fmt.Printf("Call %s(), context: %p\n", name, ctx)
 | 
					 | 
				
			||||||
	params := make([]any, len(self.children), len(self.children)+5)
 | 
						params := make([]any, len(self.children), len(self.children)+5)
 | 
				
			||||||
	for i, tree := range self.children {
 | 
						for i, tree := range self.children {
 | 
				
			||||||
		var param any
 | 
							var param any
 | 
				
			||||||
@ -85,20 +83,6 @@ func newFuncDefTerm(tk *Token, args []*term) *term {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// -------- eval func def
 | 
					// -------- eval func def
 | 
				
			||||||
// func _evalFuncDef(ctx ExprContext, self *term) (v any, err error) {
 | 
					 | 
				
			||||||
// 	bodySpec := self.value()
 | 
					 | 
				
			||||||
// 	if expr, ok := bodySpec.(*ast); ok {
 | 
					 | 
				
			||||||
// 		paramList := make([]string, 0, len(self.children))
 | 
					 | 
				
			||||||
// 		for _, param := range self.children {
 | 
					 | 
				
			||||||
// 			paramList = append(paramList, param.source())
 | 
					 | 
				
			||||||
// 		}
 | 
					 | 
				
			||||||
// 		v = newExprFunctor(expr, paramList, ctx)
 | 
					 | 
				
			||||||
// 	} else {
 | 
					 | 
				
			||||||
// 		err = errors.New("invalid function definition: the body specification must be an expression")
 | 
					 | 
				
			||||||
// 	}
 | 
					 | 
				
			||||||
// 	return
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func evalFuncDef(ctx ExprContext, self *term) (v any, err error) {
 | 
					func evalFuncDef(ctx ExprContext, self *term) (v any, err error) {
 | 
				
			||||||
	bodySpec := self.value()
 | 
						bodySpec := self.value()
 | 
				
			||||||
	if expr, ok := bodySpec.(*ast); ok {
 | 
						if expr, ok := bodySpec.(*ast); ok {
 | 
				
			||||||
 | 
				
			|||||||
@ -148,23 +148,6 @@ func evalIterator(ctx ExprContext, self *term) (v any, err error) {
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// func evalChildren(ctx ExprContext, terms []*term, firstChildValue any) (list *ListType, err error) {
 | 
					 | 
				
			||||||
// 	items := make(ListType, len(terms))
 | 
					 | 
				
			||||||
// 	for i, tree := range terms {
 | 
					 | 
				
			||||||
// 		var param any
 | 
					 | 
				
			||||||
// 		if i == 0 && firstChildValue != nil {
 | 
					 | 
				
			||||||
// 			param = firstChildValue
 | 
					 | 
				
			||||||
// 		} else if param, err = tree.compute(ctx); err != nil {
 | 
					 | 
				
			||||||
// 			break
 | 
					 | 
				
			||||||
// 		}
 | 
					 | 
				
			||||||
// 		items[i] = param
 | 
					 | 
				
			||||||
// 	}
 | 
					 | 
				
			||||||
// 	if err == nil {
 | 
					 | 
				
			||||||
// 		list = &items
 | 
					 | 
				
			||||||
// 	}
 | 
					 | 
				
			||||||
// 	return
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func evalSibling(ctx ExprContext, terms []*term, firstChildValue any) (list []any, err error) {
 | 
					func evalSibling(ctx ExprContext, terms []*term, firstChildValue any) (list []any, err error) {
 | 
				
			||||||
	items := make([]any, 0, len(terms))
 | 
						items := make([]any, 0, len(terms))
 | 
				
			||||||
	for i, tree := range terms {
 | 
						for i, tree := range terms {
 | 
				
			||||||
 | 
				
			|||||||
@ -16,14 +16,59 @@ func newAssignTerm(tk *Token) (inst *term) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func assignCollectionItem(ctx ExprContext, collectionTerm, keyListTerm *term, value any) (err error) {
 | 
				
			||||||
 | 
						var collectionValue, keyListValue, keyValue any
 | 
				
			||||||
 | 
						var keyList *ListType
 | 
				
			||||||
 | 
						var ok bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if collectionValue, err = collectionTerm.compute(ctx); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if keyListValue, err = keyListTerm.compute(ctx); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						} else if keyList, ok = keyListValue.(*ListType); !ok || len(*keyList) != 1 {
 | 
				
			||||||
 | 
							err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, typeName(keyListValue))
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if keyValue = (*keyList)[0]; keyValue == nil {
 | 
				
			||||||
 | 
							err = keyListTerm.Errorf("index/key is nil")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch collection := collectionValue.(type) {
 | 
				
			||||||
 | 
						case *ListType:
 | 
				
			||||||
 | 
							if index, ok := keyValue.(int64); ok {
 | 
				
			||||||
 | 
								err = collection.setItem(index, value)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, typeName(keyValue))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case *DictType:
 | 
				
			||||||
 | 
							err = collection.setItem(keyValue, value)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							err = collectionTerm.Errorf("collection expected")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func assignValue(ctx ExprContext, leftTerm *term, v any) (err error) {
 | 
				
			||||||
 | 
						if leftTerm.symbol() == SymIndex {
 | 
				
			||||||
 | 
							err = assignCollectionItem(ctx, leftTerm.children[0], leftTerm.children[1], v)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ctx.UnsafeSetVar(leftTerm.source(), v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func evalAssign(ctx ExprContext, self *term) (v any, err error) {
 | 
					func evalAssign(ctx ExprContext, self *term) (v any, err error) {
 | 
				
			||||||
	if err = self.checkOperands(); err != nil {
 | 
						if err = self.checkOperands(); err != nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	leftTerm := self.children[0]
 | 
						leftTerm := self.children[0]
 | 
				
			||||||
	if leftTerm.tk.Sym != SymVariable {
 | 
						leftSym := leftTerm.symbol()
 | 
				
			||||||
		err = leftTerm.tk.Errorf("left operand of %q must be a variable", self.tk.source)
 | 
						if leftSym != SymVariable && leftSym != SymIndex {
 | 
				
			||||||
 | 
							err = leftTerm.tk.Errorf("left operand of %q must be a variable or a collection's item", self.tk.source)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -31,22 +76,22 @@ func evalAssign(ctx ExprContext, self *term) (v any, err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if v, err = rightChild.compute(ctx); err == nil {
 | 
						if v, err = rightChild.compute(ctx); err == nil {
 | 
				
			||||||
		if functor, ok := v.(Functor); ok {
 | 
							if functor, ok := v.(Functor); ok {
 | 
				
			||||||
			funcName := rightChild.source()
 | 
								if info := functor.GetFunc(); info != nil {
 | 
				
			||||||
			if info, exists, _ := GetFuncInfo(ctx, funcName); exists {
 | 
					 | 
				
			||||||
				// ctx.RegisterFuncInfo(info)
 | 
					 | 
				
			||||||
				ctx.RegisterFunc(leftTerm.source(), info.Functor(), info.ReturnType(), info.Params())
 | 
									ctx.RegisterFunc(leftTerm.source(), info.Functor(), info.ReturnType(), info.Params())
 | 
				
			||||||
			} else if funcDef, ok := functor.(*exprFunctor); ok {
 | 
								} else if funcDef, ok := functor.(*exprFunctor); ok {
 | 
				
			||||||
				// paramSpecs := ForAll(funcDef.params, newFuncParam)
 | 
					 | 
				
			||||||
				paramSpecs := ForAll(funcDef.params, func(p ExprFuncParam) ExprFuncParam { return p })
 | 
									paramSpecs := ForAll(funcDef.params, func(p ExprFuncParam) ExprFuncParam { return p })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				ctx.RegisterFunc(leftTerm.source(), functor, typeAny, paramSpecs)
 | 
									ctx.RegisterFunc(leftTerm.source(), functor, typeAny, paramSpecs)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				err = self.Errorf("unknown function %s()", funcName)
 | 
									err = self.Errorf("unknown function %s()", rightChild.source())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			ctx.UnsafeSetVar(leftTerm.source(), v)
 | 
								err = assignValue(ctx, leftTerm, v)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							v = nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										23
									
								
								parser.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								parser.go
									
									
									
									
									
								
							@ -6,7 +6,6 @@ package expr
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//-------- parser
 | 
					//-------- parser
 | 
				
			||||||
@ -335,7 +334,7 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
 | 
				
			|||||||
	var tk *Token
 | 
						var tk *Token
 | 
				
			||||||
	tree = NewAst()
 | 
						tree = NewAst()
 | 
				
			||||||
	firstToken := true
 | 
						firstToken := true
 | 
				
			||||||
	lastSym := SymUnknown
 | 
						// lastSym := SymUnknown
 | 
				
			||||||
	for tk = scanner.Next(); err == nil && tk != nil && !tk.IsTerm(termSymbols); tk = scanner.Next() {
 | 
						for tk = scanner.Next(); err == nil && tk != nil && !tk.IsTerm(termSymbols); tk = scanner.Next() {
 | 
				
			||||||
		if tk.Sym == SymComment {
 | 
							if tk.Sym == SymComment {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
@ -404,9 +403,9 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case SymEqual:
 | 
							case SymEqual:
 | 
				
			||||||
			if err = checkPrevSymbol(lastSym, SymIdentifier, tk); err == nil {
 | 
								// if err = checkPrevSymbol(lastSym, SymIdentifier, tk); err == nil {
 | 
				
			||||||
				currentTerm, err = tree.addToken2(tk)
 | 
								currentTerm, err = tree.addToken2(tk)
 | 
				
			||||||
			}
 | 
								// }
 | 
				
			||||||
		case SymFuncDef:
 | 
							case SymFuncDef:
 | 
				
			||||||
			var funcDefTerm *term
 | 
								var funcDefTerm *term
 | 
				
			||||||
			if funcDefTerm, err = self.parseFuncDef(scanner); err == nil {
 | 
								if funcDefTerm, err = self.parseFuncDef(scanner); err == nil {
 | 
				
			||||||
@ -450,7 +449,7 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
 | 
				
			|||||||
			selectorTerm = nil
 | 
								selectorTerm = nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		lastSym = tk.Sym
 | 
							// lastSym = tk.Sym
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		err = tk.Error()
 | 
							err = tk.Error()
 | 
				
			||||||
@ -458,9 +457,9 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func checkPrevSymbol(lastSym, wantedSym Symbol, tk *Token) (err error) {
 | 
					// func checkPrevSymbol(lastSym, wantedSym Symbol, tk *Token) (err error) {
 | 
				
			||||||
	if lastSym != wantedSym {
 | 
					// 	if lastSym != wantedSym {
 | 
				
			||||||
		err = fmt.Errorf(`assign operator (%q) must be preceded by a variable`, tk.source)
 | 
					// 		err = fmt.Errorf(`assign operator (%q) must be preceded by a variable`, tk.source)
 | 
				
			||||||
	}
 | 
					// 	}
 | 
				
			||||||
	return
 | 
					// 	return
 | 
				
			||||||
}
 | 
					// }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,244 +0,0 @@
 | 
				
			|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 | 
					 | 
				
			||||||
// All rights reserved.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// simple-func-store.go
 | 
					 | 
				
			||||||
package expr
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"slices"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type SimpleFuncStore struct {
 | 
					 | 
				
			||||||
	SimpleVarStore
 | 
					 | 
				
			||||||
	funcStore map[string]*funcInfo
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type paramFlags uint16
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	pfOptional paramFlags = 1 << iota
 | 
					 | 
				
			||||||
	pfRepeat
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type funcParamInfo struct {
 | 
					 | 
				
			||||||
	name         string
 | 
					 | 
				
			||||||
	flags        paramFlags
 | 
					 | 
				
			||||||
	defaultValue any
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newFuncParam(name string) *funcParamInfo {
 | 
					 | 
				
			||||||
	return &funcParamInfo{name: name}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newFuncParamFlag(name string, flags paramFlags) *funcParamInfo {
 | 
					 | 
				
			||||||
	return &funcParamInfo{name: name, flags: flags}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newFuncParamFlagDef(name string, flags paramFlags, defValue any) *funcParamInfo {
 | 
					 | 
				
			||||||
	return &funcParamInfo{name: name, flags: flags, defaultValue: defValue}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (param *funcParamInfo) Name() string {
 | 
					 | 
				
			||||||
	return param.name
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (param *funcParamInfo) Type() string {
 | 
					 | 
				
			||||||
	return "any"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (param *funcParamInfo) IsOptional() bool {
 | 
					 | 
				
			||||||
	return (param.flags & pfOptional) != 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (param *funcParamInfo) IsRepeat() bool {
 | 
					 | 
				
			||||||
	return (param.flags & pfRepeat) != 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (param *funcParamInfo) DefaultValue() any {
 | 
					 | 
				
			||||||
	return param.defaultValue
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type funcInfo struct {
 | 
					 | 
				
			||||||
	name       string
 | 
					 | 
				
			||||||
	minArgs    int
 | 
					 | 
				
			||||||
	maxArgs    int
 | 
					 | 
				
			||||||
	functor    Functor
 | 
					 | 
				
			||||||
	params     []ExprFuncParam
 | 
					 | 
				
			||||||
	returnType string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (info *funcInfo) Params() []ExprFuncParam {
 | 
					 | 
				
			||||||
	return info.params
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (info *funcInfo) ReturnType() string {
 | 
					 | 
				
			||||||
	return info.returnType
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (info *funcInfo) ToString(opt FmtOpt) string {
 | 
					 | 
				
			||||||
	var sb strings.Builder
 | 
					 | 
				
			||||||
	sb.WriteByte('(')
 | 
					 | 
				
			||||||
	if info.params != nil {
 | 
					 | 
				
			||||||
		for i, p := range info.params {
 | 
					 | 
				
			||||||
			if i > 0 {
 | 
					 | 
				
			||||||
				sb.WriteString(", ")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			sb.WriteString(p.Name())
 | 
					 | 
				
			||||||
			if p.IsOptional() {
 | 
					 | 
				
			||||||
				sb.WriteByte('=')
 | 
					 | 
				
			||||||
				if s, ok := p.DefaultValue().(string); ok {
 | 
					 | 
				
			||||||
					sb.WriteByte('"')
 | 
					 | 
				
			||||||
					sb.WriteString(s)
 | 
					 | 
				
			||||||
					sb.WriteByte('"')
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					sb.WriteString(fmt.Sprintf("%v", p.DefaultValue()))
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if info.maxArgs < 0 {
 | 
					 | 
				
			||||||
		sb.WriteString(" ...")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sb.WriteString(") -> ")
 | 
					 | 
				
			||||||
	if len(info.returnType) > 0 {
 | 
					 | 
				
			||||||
		sb.WriteString(info.returnType)
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		sb.WriteString(typeAny)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return sb.String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (info *funcInfo) Name() string {
 | 
					 | 
				
			||||||
	return info.name
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (info *funcInfo) MinArgs() int {
 | 
					 | 
				
			||||||
	return info.minArgs
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (info *funcInfo) MaxArgs() int {
 | 
					 | 
				
			||||||
	return info.maxArgs
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (info *funcInfo) Functor() Functor {
 | 
					 | 
				
			||||||
	return info.functor
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewSimpleFuncStore() *SimpleFuncStore {
 | 
					 | 
				
			||||||
	ctx := &SimpleFuncStore{
 | 
					 | 
				
			||||||
		SimpleVarStore: SimpleVarStore{varStore: make(map[string]any)},
 | 
					 | 
				
			||||||
		funcStore:      make(map[string]*funcInfo),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	//ImportBuiltinsFuncs(ctx)
 | 
					 | 
				
			||||||
	return ctx
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleFuncStore) Clone() ExprContext {
 | 
					 | 
				
			||||||
	svs := ctx.SimpleVarStore
 | 
					 | 
				
			||||||
	return &SimpleFuncStore{
 | 
					 | 
				
			||||||
		// SimpleVarStore: SimpleVarStore{varStore: CloneMap(ctx.varStore)},
 | 
					 | 
				
			||||||
		SimpleVarStore: SimpleVarStore{varStore: svs.cloneVars()},
 | 
					 | 
				
			||||||
		funcStore:      CloneFilteredMap(ctx.funcStore, func(name string) bool { return name[0] != '@' }),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func funcsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
 | 
					 | 
				
			||||||
	sb.WriteString("funcs: {\n")
 | 
					 | 
				
			||||||
	first := true
 | 
					 | 
				
			||||||
	names := ctx.EnumFuncs(func(name string) bool { return true })
 | 
					 | 
				
			||||||
	slices.Sort(names)
 | 
					 | 
				
			||||||
	for _, name := range names {
 | 
					 | 
				
			||||||
		if first {
 | 
					 | 
				
			||||||
			first = false
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			sb.WriteByte(',')
 | 
					 | 
				
			||||||
			sb.WriteByte('\n')
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		value, _ := ctx.GetFuncInfo(name)
 | 
					 | 
				
			||||||
		sb.WriteString(strings.Repeat("\t", indent+1))
 | 
					 | 
				
			||||||
		sb.WriteString(name)
 | 
					 | 
				
			||||||
		//sb.WriteString("=")
 | 
					 | 
				
			||||||
		if formatter, ok := value.(Formatter); ok {
 | 
					 | 
				
			||||||
			sb.WriteString(formatter.ToString(0))
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			sb.WriteString(fmt.Sprintf("%v", value))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sb.WriteString("\n}\n")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleFuncStore) ToString(opt FmtOpt) string {
 | 
					 | 
				
			||||||
	var sb strings.Builder
 | 
					 | 
				
			||||||
	sb.WriteString(ctx.SimpleVarStore.ToString(opt))
 | 
					 | 
				
			||||||
	funcsCtxToBuilder(&sb, ctx, 0)
 | 
					 | 
				
			||||||
	return sb.String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleFuncStore) GetFuncInfo(name string) (info ExprFunc, exists bool) {
 | 
					 | 
				
			||||||
	info, exists = ctx.funcStore[name]
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// func (ctx *SimpleFuncStore) RegisterFunc(name string, functor Functor, minArgs, maxArgs int) {
 | 
					 | 
				
			||||||
// 	ctx.funcStore[name] = &funcInfo{name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor}
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleFuncStore) RegisterFuncInfo(info ExprFunc) {
 | 
					 | 
				
			||||||
	ctx.funcStore[info.Name()], _ = info.(*funcInfo)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleFuncStore) RegisterFunc2(name string, functor Functor, returnType string, params []ExprFuncParam) error {
 | 
					 | 
				
			||||||
	var minArgs = 0
 | 
					 | 
				
			||||||
	var maxArgs = 0
 | 
					 | 
				
			||||||
	if params != nil {
 | 
					 | 
				
			||||||
		for _, p := range params {
 | 
					 | 
				
			||||||
			if maxArgs == -1 {
 | 
					 | 
				
			||||||
				return fmt.Errorf("no more params can be specified after the ellipsis symbol: %q", p.Name())
 | 
					 | 
				
			||||||
				// } else if p.IsRepeat() {
 | 
					 | 
				
			||||||
				// 	maxArgs = -1
 | 
					 | 
				
			||||||
				// 	continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if p.IsOptional() {
 | 
					 | 
				
			||||||
				maxArgs++
 | 
					 | 
				
			||||||
			} else if maxArgs == minArgs {
 | 
					 | 
				
			||||||
				minArgs++
 | 
					 | 
				
			||||||
				maxArgs++
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				return fmt.Errorf("can't specify non-optional param after optional ones: %q", p.Name())
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if p.IsRepeat() {
 | 
					 | 
				
			||||||
				maxArgs = -1
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctx.funcStore[name] = &funcInfo{
 | 
					 | 
				
			||||||
		name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, params: params,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleFuncStore) EnumFuncs(acceptor func(name string) (accept bool)) (funcNames []string) {
 | 
					 | 
				
			||||||
	funcNames = make([]string, 0)
 | 
					 | 
				
			||||||
	for name := range ctx.funcStore {
 | 
					 | 
				
			||||||
		if acceptor != nil {
 | 
					 | 
				
			||||||
			if acceptor(name) {
 | 
					 | 
				
			||||||
				funcNames = append(funcNames, name)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			funcNames = append(funcNames, name)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleFuncStore) Call(name string, args []any) (result any, err error) {
 | 
					 | 
				
			||||||
	if info, exists := ctx.funcStore[name]; exists {
 | 
					 | 
				
			||||||
		functor := info.functor
 | 
					 | 
				
			||||||
		result, err = functor.Invoke(ctx, name, args)
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		err = fmt.Errorf("unknown function %s()", name)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -172,7 +172,7 @@ func (ctx *SimpleStore) EnumFuncs(acceptor func(name string) (accept bool)) (fun
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ctx *SimpleStore) Call(name string, args []any) (result any, err error) {
 | 
					func (ctx *SimpleStore) Call(name string, args []any) (result any, err error) {
 | 
				
			||||||
	if info, exists := ctx.funcStore[name]; exists {
 | 
						if info, exists := GetLocalFuncInfo(ctx, name); exists {
 | 
				
			||||||
		functor := info.Functor()
 | 
							functor := info.Functor()
 | 
				
			||||||
		result, err = functor.Invoke(ctx, name, args)
 | 
							result, err = functor.Invoke(ctx, name, args)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,126 +0,0 @@
 | 
				
			|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 | 
					 | 
				
			||||||
// All rights reserved.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// simple-var-store.go
 | 
					 | 
				
			||||||
package expr
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type SimpleVarStore struct {
 | 
					 | 
				
			||||||
	varStore map[string]any
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewSimpleVarStore() *SimpleVarStore {
 | 
					 | 
				
			||||||
	return &SimpleVarStore{
 | 
					 | 
				
			||||||
		varStore: make(map[string]any),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) cloneVars() (vars map[string]any) {
 | 
					 | 
				
			||||||
	return CloneFilteredMap(ctx.varStore, func(name string) bool { return name[0] != '@' })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) Clone() (clone ExprContext) {
 | 
					 | 
				
			||||||
	// fmt.Println("*** Cloning context ***")
 | 
					 | 
				
			||||||
	clone = &SimpleVarStore{
 | 
					 | 
				
			||||||
		varStore: ctx.cloneVars(),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return clone
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) GetVar(varName string) (v any, exists bool) {
 | 
					 | 
				
			||||||
	v, exists = ctx.varStore[varName]
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) UnsafeSetVar(varName string, value any) {
 | 
					 | 
				
			||||||
	// fmt.Printf("[%p] setVar(%v, %v)\n", ctx, varName, value)
 | 
					 | 
				
			||||||
	ctx.varStore[varName] = value
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) SetVar(varName string, value any) {
 | 
					 | 
				
			||||||
	// fmt.Printf("[%p] SetVar(%v, %v)\n", ctx, varName, value)
 | 
					 | 
				
			||||||
	if allowedValue, ok := fromGenericAny(value); ok {
 | 
					 | 
				
			||||||
		ctx.varStore[varName] = allowedValue
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		panic(fmt.Errorf("unsupported type %T of value %v", value, value))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) EnumVars(acceptor func(name string) (accept bool)) (varNames []string) {
 | 
					 | 
				
			||||||
	varNames = make([]string, 0)
 | 
					 | 
				
			||||||
	for name := range ctx.varStore {
 | 
					 | 
				
			||||||
		if acceptor != nil {
 | 
					 | 
				
			||||||
			if acceptor(name) {
 | 
					 | 
				
			||||||
				varNames = append(varNames, name)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			varNames = append(varNames, name)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) GetFuncInfo(name string) (f ExprFunc, exists bool) {
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) Call(name string, args []any) (result any, err error) {
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// func (ctx *SimpleVarStore) RegisterFunc(name string, functor Functor, minArgs, maxArgs int) {
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) RegisterFuncInfo(info ExprFunc) {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) RegisterFunc2(name string, f Functor, returnType string, param []ExprFuncParam) error {
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) EnumFuncs(acceptor func(name string) (accept bool)) (funcNames []string) {
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
 | 
					 | 
				
			||||||
	sb.WriteString("vars: {\n")
 | 
					 | 
				
			||||||
	first := true
 | 
					 | 
				
			||||||
	for _, name := range ctx.EnumVars(func(name string) bool { return name[0] != '_' }) {
 | 
					 | 
				
			||||||
		if first {
 | 
					 | 
				
			||||||
			first = false
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			sb.WriteByte(',')
 | 
					 | 
				
			||||||
			sb.WriteByte('\n')
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		value, _ := ctx.GetVar(name)
 | 
					 | 
				
			||||||
		sb.WriteString(strings.Repeat("\t", indent+1))
 | 
					 | 
				
			||||||
		sb.WriteString(name)
 | 
					 | 
				
			||||||
		sb.WriteString(": ")
 | 
					 | 
				
			||||||
		if f, ok := value.(Formatter); ok {
 | 
					 | 
				
			||||||
			sb.WriteString(f.ToString(0))
 | 
					 | 
				
			||||||
		} else if _, ok = value.(Functor); ok {
 | 
					 | 
				
			||||||
			sb.WriteString("func(){}")
 | 
					 | 
				
			||||||
			// } else if _, ok = value.(map[any]any); ok {
 | 
					 | 
				
			||||||
			// 	sb.WriteString("dict{}")
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			sb.WriteString(fmt.Sprintf("%v", value))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sb.WriteString(strings.Repeat("\t", indent))
 | 
					 | 
				
			||||||
	sb.WriteString("\n}\n")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func varsCtxToString(ctx ExprContext, indent int) string {
 | 
					 | 
				
			||||||
	var sb strings.Builder
 | 
					 | 
				
			||||||
	varsCtxToBuilder(&sb, ctx, indent)
 | 
					 | 
				
			||||||
	return sb.String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleVarStore) ToString(opt FmtOpt) string {
 | 
					 | 
				
			||||||
	var sb strings.Builder
 | 
					 | 
				
			||||||
	varsCtxToBuilder(&sb, ctx, 0)
 | 
					 | 
				
			||||||
	return sb.String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -28,6 +28,9 @@ func TestDictParser(t *testing.T) {
 | 
				
			|||||||
		/*  5 */ {`#{1:"one",2:"two",3:"three"}`, int64(3), nil},
 | 
							/*  5 */ {`#{1:"one",2:"two",3:"three"}`, int64(3), nil},
 | 
				
			||||||
		/*  6 */ {`{1:"one"} + {2:"two"}`, map[any]any{1: "one", 2: "two"}, nil},
 | 
							/*  6 */ {`{1:"one"} + {2:"two"}`, map[any]any{1: "one", 2: "two"}, nil},
 | 
				
			||||||
		/*  7 */ {`2 in {1:"one", 2:"two"}`, true, nil},
 | 
							/*  7 */ {`2 in {1:"one", 2:"two"}`, true, nil},
 | 
				
			||||||
 | 
							/*  8 */ {`D={"a":1, "b":2}; D["a"]=9; D`, map[any]any{"a": 9, "b": 2}, nil},
 | 
				
			||||||
 | 
							/*  9 */ {`D={"a":1, "b":2}; D["z"]=9; D`, map[any]any{"z": 9, "a": 1, "b": 2}, nil},
 | 
				
			||||||
 | 
							/* 10 */ {`D={"a":1, "b":2}; D[nil]=9`, nil, errors.New(`[1:21] index/key is nil`)},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	succeeded := 0
 | 
						succeeded := 0
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ func TestFuncBase(t *testing.T) {
 | 
				
			|||||||
		/*   8 */ {`int("432")`, int64(432), nil},
 | 
							/*   8 */ {`int("432")`, int64(432), nil},
 | 
				
			||||||
		/*   9 */ {`int("1.5")`, nil, errors.New(`strconv.Atoi: parsing "1.5": invalid syntax`)},
 | 
							/*   9 */ {`int("1.5")`, nil, errors.New(`strconv.Atoi: parsing "1.5": invalid syntax`)},
 | 
				
			||||||
		/*  10 */ {`int("432", 4)`, nil, errors.New(`int(): too much params -- expected 1, got 2`)},
 | 
							/*  10 */ {`int("432", 4)`, nil, errors.New(`int(): too much params -- expected 1, got 2`)},
 | 
				
			||||||
		/*  11 */ {`int(nil)`, nil, errors.New(`int(): can't convert <nil> to int`)},
 | 
							/*  11 */ {`int(nil)`, nil, errors.New(`int(): can't convert nil to int`)},
 | 
				
			||||||
		/*  12 */ {`isInt(2+1)`, true, nil},
 | 
							/*  12 */ {`isInt(2+1)`, true, nil},
 | 
				
			||||||
		/*  13 */ {`isInt(3.1)`, false, nil},
 | 
							/*  13 */ {`isInt(3.1)`, false, nil},
 | 
				
			||||||
		/*  14 */ {`isFloat(3.1)`, true, nil},
 | 
							/*  14 */ {`isFloat(3.1)`, true, nil},
 | 
				
			||||||
 | 
				
			|||||||
@ -16,8 +16,8 @@ func TestFuncString(t *testing.T) {
 | 
				
			|||||||
		/*   1 */ {`builtin "string"; joinStr("-", "one", "two", "three")`, "one-two-three", nil},
 | 
							/*   1 */ {`builtin "string"; joinStr("-", "one", "two", "three")`, "one-two-three", nil},
 | 
				
			||||||
		/*   2 */ {`builtin "string"; joinStr("-", ["one", "two", "three"])`, "one-two-three", nil},
 | 
							/*   2 */ {`builtin "string"; joinStr("-", ["one", "two", "three"])`, "one-two-three", nil},
 | 
				
			||||||
		/*   3 */ {`builtin "string"; ls= ["one", "two", "three"]; joinStr("-", ls)`, "one-two-three", nil},
 | 
							/*   3 */ {`builtin "string"; ls= ["one", "two", "three"]; joinStr("-", ls)`, "one-two-three", nil},
 | 
				
			||||||
		/*   4 */ {`builtin "string"; ls= ["one", "two", "three"]; joinStr(1, ls)`, nil, errors.New(`joinStr() the "separator" parameter must be a string, got a int64 (1)`)},
 | 
							/*   4 */ {`builtin "string"; ls= ["one", "two", "three"]; joinStr(1, ls)`, nil, errors.New(`joinStr() the "separator" parameter must be a string, got a integer (1)`)},
 | 
				
			||||||
		/*   5 */ {`builtin "string"; ls= ["one", 2, "three"]; joinStr("-", ls)`, nil, errors.New(`joinStr() expected string, got int64 (2)`)},
 | 
							/*   5 */ {`builtin "string"; ls= ["one", 2, "three"]; joinStr("-", ls)`, nil, errors.New(`joinStr() expected string, got integer (2)`)},
 | 
				
			||||||
		/*   6 */ {`builtin "string"; "<"+trimStr("  bye bye  ")+">"`, "<bye bye>", nil},
 | 
							/*   6 */ {`builtin "string"; "<"+trimStr("  bye bye  ")+">"`, "<bye bye>", nil},
 | 
				
			||||||
		/*   7 */ {`builtin "string"; subStr("0123456789", 1,2)`, "12", nil},
 | 
							/*   7 */ {`builtin "string"; subStr("0123456789", 1,2)`, "12", nil},
 | 
				
			||||||
		/*   8 */ {`builtin "string"; subStr("0123456789", -3,2)`, "78", nil},
 | 
							/*   8 */ {`builtin "string"; subStr("0123456789", -3,2)`, "78", nil},
 | 
				
			||||||
@ -30,7 +30,7 @@ func TestFuncString(t *testing.T) {
 | 
				
			|||||||
		/*  15 */ {`builtin "string"; endsWithStr("0123456789", "xyz", "0125")`, false, nil},
 | 
							/*  15 */ {`builtin "string"; endsWithStr("0123456789", "xyz", "0125")`, false, nil},
 | 
				
			||||||
		/*  16 */ {`builtin "string"; endsWithStr("0123456789")`, nil, errors.New(`endsWithStr(): too few params -- expected 2 or more, got 1`)},
 | 
							/*  16 */ {`builtin "string"; endsWithStr("0123456789")`, nil, errors.New(`endsWithStr(): too few params -- expected 2 or more, got 1`)},
 | 
				
			||||||
		/*  17 */ {`builtin "string"; splitStr("one-two-three", "-")`, newListA("one", "two", "three"), nil},
 | 
							/*  17 */ {`builtin "string"; splitStr("one-two-three", "-")`, newListA("one", "two", "three"), nil},
 | 
				
			||||||
		/*  18 */ {`builtin "string"; joinStr("-", [1, "two", "three"])`, nil, errors.New(`joinStr() expected string, got int64 (1)`)},
 | 
							/*  18 */ {`builtin "string"; joinStr("-", [1, "two", "three"])`, nil, errors.New(`joinStr() expected string, got integer (1)`)},
 | 
				
			||||||
		/*  19 */ {`builtin "string"; joinStr()`, nil, errors.New(`joinStr(): too few params -- expected 1 or more, got 0`)},
 | 
							/*  19 */ {`builtin "string"; joinStr()`, nil, errors.New(`joinStr(): too few params -- expected 1 or more, got 0`)},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*  69 */ /*{`builtin "string"; $$global`, `vars: {
 | 
							/*  69 */ /*{`builtin "string"; $$global`, `vars: {
 | 
				
			||||||
 | 
				
			|||||||
@ -13,26 +13,26 @@ import (
 | 
				
			|||||||
func TestListParser(t *testing.T) {
 | 
					func TestListParser(t *testing.T) {
 | 
				
			||||||
	section := "List"
 | 
						section := "List"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	type inputType struct {
 | 
						/*	type inputType struct {
 | 
				
			||||||
		source     string
 | 
								source     string
 | 
				
			||||||
		wantResult any
 | 
								wantResult any
 | 
				
			||||||
		wantErr    error
 | 
								wantErr    error
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
	inputs := []inputType{
 | 
						inputs := []inputType{
 | 
				
			||||||
		/*   1 */ {`[]`, []any{}, nil},
 | 
							/*   1 */ {`[]`, newListA(), nil},
 | 
				
			||||||
		/*   2 */ {`[1,2,3]`, []any{int64(1), int64(2), int64(3)}, nil},
 | 
							/*   2 */ {`[1,2,3]`, newListA(int64(1), int64(2), int64(3)), nil},
 | 
				
			||||||
		/*   3 */ {`[1,2,"hello"]`, []any{int64(1), int64(2), "hello"}, nil},
 | 
							/*   3 */ {`[1,2,"hello"]`, newListA(int64(1), int64(2), "hello"), nil},
 | 
				
			||||||
		/*   4 */ {`[1+2, not true, "hello"]`, []any{int64(3), false, "hello"}, nil},
 | 
							/*   4 */ {`[1+2, not true, "hello"]`, newListA(int64(3), false, "hello"), nil},
 | 
				
			||||||
		/*   5 */ {`[1,2]+[3]`, []any{int64(1), int64(2), int64(3)}, nil},
 | 
							/*   5 */ {`[1,2]+[3]`, newListA(int64(1), int64(2), int64(3)), nil},
 | 
				
			||||||
		/*   6 */ {`[1,4,3,2]-[3]`, []any{int64(1), int64(4), int64(2)}, nil},
 | 
							/*   6 */ {`[1,4,3,2]-[3]`, newListA(int64(1), int64(4), int64(2)), nil},
 | 
				
			||||||
		/*   7 */ {`add([1,4,3,2])`, int64(10), nil},
 | 
							/*   7 */ {`add([1,4,3,2])`, int64(10), nil},
 | 
				
			||||||
		/*   8 */ {`add([1,[2,2],3,2])`, int64(10), nil},
 | 
							/*   8 */ {`add([1,[2,2],3,2])`, int64(10), nil},
 | 
				
			||||||
		/*   9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil},
 | 
							/*   9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil},
 | 
				
			||||||
		/*  10 */ {`add([1,"hello"])`, nil, errors.New(`add(): param nr 2 (2 in 1) has wrong type string, number expected`)},
 | 
							/*  10 */ {`add([1,"hello"])`, nil, errors.New(`add(): param nr 2 (2 in 1) has wrong type string, number expected`)},
 | 
				
			||||||
		/*  11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil},
 | 
							/*  11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil},
 | 
				
			||||||
		/*  12 */ {`[1,2,3] << 2+2`, []any{int64(1), int64(2), int64(3), int64(4)}, nil},
 | 
							/*  12 */ {`[1,2,3] << 2+2`, newListA(int64(1), int64(2), int64(3), int64(4)), nil},
 | 
				
			||||||
		/*  13 */ {`2-1 >> [2,3]`, []any{int64(1), int64(2), int64(3)}, nil},
 | 
							/*  13 */ {`2-1 >> [2,3]`, newListA(int64(1), int64(2), int64(3)), nil},
 | 
				
			||||||
		/*  14 */ {`[1,2,3][1]`, int64(2), nil},
 | 
							/*  14 */ {`[1,2,3][1]`, int64(2), nil},
 | 
				
			||||||
		/*  15 */ {`ls=[1,2,3] but ls[1]`, int64(2), nil},
 | 
							/*  15 */ {`ls=[1,2,3] but ls[1]`, int64(2), nil},
 | 
				
			||||||
		/*  16 */ {`ls=[1,2,3] but ls[-1]`, int64(3), nil},
 | 
							/*  16 */ {`ls=[1,2,3] but ls[-1]`, int64(3), nil},
 | 
				
			||||||
@ -41,22 +41,30 @@ func TestListParser(t *testing.T) {
 | 
				
			|||||||
		/*  19 */ {`["a", "b", "c"]`, newList([]any{"a", "b", "c"}), nil},
 | 
							/*  19 */ {`["a", "b", "c"]`, newList([]any{"a", "b", "c"}), nil},
 | 
				
			||||||
		/*  20 */ {`#["a", "b", "c"]`, int64(3), nil},
 | 
							/*  20 */ {`#["a", "b", "c"]`, int64(3), nil},
 | 
				
			||||||
		/*  21 */ {`"b" in ["a", "b", "c"]`, true, nil},
 | 
							/*  21 */ {`"b" in ["a", "b", "c"]`, true, nil},
 | 
				
			||||||
		/*  22 */ {`a=[1,2]; (a)<<3`, []any{1, 2, 3}, nil},
 | 
							/*  22 */ {`a=[1,2]; (a)<<3`, newListA(int64(1), int64(2), int64(3)), nil},
 | 
				
			||||||
		/*  23 */ {`a=[1,2]; (a)<<3; 1`, []any{1, 2}, nil},
 | 
							/*  23 */ {`a=[1,2]; (a)<<3; a`, newListA(int64(1), int64(2)), nil},
 | 
				
			||||||
		/*  24 */ {`["a","b","c","d"][1]`, "b", nil},
 | 
							/*  24 */ {`["a","b","c","d"][1]`, "b", nil},
 | 
				
			||||||
		/*  25 */ {`["a","b","c","d"][1,1]`, nil, errors.New(`[1:19] one index only is allowed`)},
 | 
							/*  25 */ {`["a","b","c","d"][1,1]`, nil, errors.New(`[1:19] one index only is allowed`)},
 | 
				
			||||||
		/*  26 */ {`[0,1,2,3,4][:]`, ListType{int64(0), int64(1), int64(2), int64(3), int64(4)}, nil},
 | 
							/*  26 */ {`[0,1,2,3,4][:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
 | 
				
			||||||
		/*  27 */ {`["a", "b", "c"] << ;`, nil, errors.New(`[1:18] infix operator "<<" requires two non-nil operands, got 1`)},
 | 
							/*  27 */ {`["a", "b", "c"] << ;`, nil, errors.New(`[1:18] infix operator "<<" requires two non-nil operands, got 1`)},
 | 
				
			||||||
		/*  28 */ {`2 << 3;`, nil, errors.New(`[1:4] left operand '2' [integer] and right operand '3' [integer] are not compatible with operator "<<"`)},
 | 
							/*  28 */ {`2 << 3;`, nil, errors.New(`[1:4] left operand '2' [integer] and right operand '3' [integer] are not compatible with operator "<<"`)},
 | 
				
			||||||
		/*  29 */ {`but >> ["a", "b", "c"]`, nil, errors.New(`[1:6] infix operator ">>" requires two non-nil operands, got 0`)},
 | 
							/*  29 */ {`but >> ["a", "b", "c"]`, nil, errors.New(`[1:6] infix operator ">>" requires two non-nil operands, got 0`)},
 | 
				
			||||||
		/*  30 */ {`2 >> 3;`, nil, errors.New(`[1:4] left operand '2' [integer] and right operand '3' [integer] are not compatible with operator ">>"`)},
 | 
							/*  30 */ {`2 >> 3;`, nil, errors.New(`[1:4] left operand '2' [integer] and right operand '3' [integer] are not compatible with operator ">>"`)},
 | 
				
			||||||
		/*  31 */ {`a=[1,2]; a<<3`, []any{1, 2, 3}, nil},
 | 
							/*  31 */ {`a=[1,2]; a<<3`, newListA(int64(1), int64(2), int64(3)), nil},
 | 
				
			||||||
		/*  33 */ {`a=[1,2]; 5>>a`, []any{5, 1, 2}, nil},
 | 
							/*  33 */ {`a=[1,2]; 5>>a`, newListA(int64(5), int64(1), int64(2)), nil},
 | 
				
			||||||
 | 
							/*  34 */ {`L=[1,2]; L[0]=9; L`, newListA(int64(9), int64(2)), nil},
 | 
				
			||||||
 | 
							/*  35 */ {`L=[1,2]; L[5]=9; L`, nil, errors.New(`index 5 out of bounds (0, 1)`)},
 | 
				
			||||||
 | 
							/*  36 */ {`L=[1,2]; L[]=9; L`, nil, errors.New(`[1:12] index/key specification expected, got [] [list]`)},
 | 
				
			||||||
 | 
							/*  37 */ {`L=[1,2]; L[nil]=9;`, nil, errors.New(`[1:12] index/key is nil`)},
 | 
				
			||||||
		// /*  8 */ {`[int(x)|x=csv("test.csv",1,all(),1)]`, []any{int64(10), int64(40), int64(20)}, nil},
 | 
							// /*  8 */ {`[int(x)|x=csv("test.csv",1,all(),1)]`, []any{int64(10), int64(40), int64(20)}, nil},
 | 
				
			||||||
		// /*  9 */ {`sum(@[int(x)|x=csv("test.csv",1,all(),1)])`, []any{int64(10), int64(40), int64(20)}, nil},
 | 
							// /*  9 */ {`sum(@[int(x)|x=csv("test.csv",1,all(),1)])`, []any{int64(10), int64(40), int64(20)}, nil},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// t.Setenv("EXPR_PATH", ".")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// parserTestSpec(t, section, inputs, 17)
 | 
				
			||||||
 | 
						parserTest(t, section, inputs)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
	succeeded := 0
 | 
						succeeded := 0
 | 
				
			||||||
	failed := 0
 | 
						failed := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,8 @@ type inputType struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGeneralParser(t *testing.T) {
 | 
					func TestGeneralParser(t *testing.T) {
 | 
				
			||||||
 | 
						section := "Parser"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inputs := []inputType{
 | 
						inputs := []inputType{
 | 
				
			||||||
		/*   1 */ {`1+/*5*/2`, int64(3), nil},
 | 
							/*   1 */ {`1+/*5*/2`, int64(3), nil},
 | 
				
			||||||
		/*   2 */ {`3 == 4`, false, nil},
 | 
							/*   2 */ {`3 == 4`, false, nil},
 | 
				
			||||||
@ -115,8 +117,8 @@ func TestGeneralParser(t *testing.T) {
 | 
				
			|||||||
		/*  94 */ {`false or true`, true, nil},
 | 
							/*  94 */ {`false or true`, true, nil},
 | 
				
			||||||
		/*  95 */ {`false or (x==2)`, nil, errors.New(`undefined variable or function "x"`)},
 | 
							/*  95 */ {`false or (x==2)`, nil, errors.New(`undefined variable or function "x"`)},
 | 
				
			||||||
		/*  96 */ {`a=5; a`, int64(5), nil},
 | 
							/*  96 */ {`a=5; a`, int64(5), nil},
 | 
				
			||||||
		/*  97 */ {`2=5`, nil, errors.New(`assign operator ("=") must be preceded by a variable`)},
 | 
							/*  97 */ {`2=5`, nil, errors.New(`[1:2] left operand of "=" must be a variable or a collection's item`)},
 | 
				
			||||||
		/*  98 */ {`2+a=5`, nil, errors.New(`[1:3] left operand of "=" must be a variable`)},
 | 
							/*  98 */ {`2+a=5`, nil, errors.New(`[1:3] left operand of "=" must be a variable or a collection's item`)},
 | 
				
			||||||
		/*  99 */ {`2+(a=5)`, int64(7), nil},
 | 
							/*  99 */ {`2+(a=5)`, int64(7), nil},
 | 
				
			||||||
		/* 100 */ {`x ?? "default"`, "default", nil},
 | 
							/* 100 */ {`x ?? "default"`, "default", nil},
 | 
				
			||||||
		/* 101 */ {`x="hello"; x ?? "default"`, "hello", nil},
 | 
							/* 101 */ {`x="hello"; x ?? "default"`, "hello", nil},
 | 
				
			||||||
@ -145,8 +147,8 @@ func TestGeneralParser(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// t.Setenv("EXPR_PATH", ".")
 | 
						// t.Setenv("EXPR_PATH", ".")
 | 
				
			||||||
	// parserTestSpec(t, "General", inputs, 102)
 | 
						// parserTestSpec(t, section, inputs, 102)
 | 
				
			||||||
	parserTest(t, "General", inputs)
 | 
						parserTest(t, section, inputs)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func parserTestSpec(t *testing.T, section string, inputs []inputType, spec ...int) {
 | 
					func parserTestSpec(t *testing.T, section string, inputs []inputType, spec ...int) {
 | 
				
			||||||
@ -201,7 +203,7 @@ func doTest(t *testing.T, section string, input *inputType, count int) (good boo
 | 
				
			|||||||
	eq := reflect.DeepEqual(gotResult, input.wantResult)
 | 
						eq := reflect.DeepEqual(gotResult, input.wantResult)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !eq /*gotResult != input.wantResult*/ {
 | 
						if !eq /*gotResult != input.wantResult*/ {
 | 
				
			||||||
		t.Errorf("%d: %q -> result = %v [%T], want = %v [%T]", count, input.source, gotResult, gotResult, input.wantResult, input.wantResult)
 | 
							t.Errorf("%d: %q -> result = %v [%s], want = %v [%s]", count, input.source, gotResult, typeName(gotResult), input.wantResult, typeName(input.wantResult))
 | 
				
			||||||
		good = false
 | 
							good = false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								term.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								term.go
									
									
									
									
									
								
							@ -156,15 +156,15 @@ func (self *term) toInt(computedValue any, valueDescription string) (i int, err
 | 
				
			|||||||
	if index64, ok := computedValue.(int64); ok {
 | 
						if index64, ok := computedValue.(int64); ok {
 | 
				
			||||||
		i = int(index64)
 | 
							i = int(index64)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		err = self.Errorf("%s, got %T (%v)", valueDescription, computedValue, computedValue)
 | 
							err = self.Errorf("%s, got %s (%v)", valueDescription, typeName(computedValue), computedValue)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *term) errIncompatibleTypes(leftValue, rightValue any) error {
 | 
					func (self *term) errIncompatibleTypes(leftValue, rightValue any) error {
 | 
				
			||||||
	leftType := getTypeName(leftValue)
 | 
						leftType := typeName(leftValue)
 | 
				
			||||||
	leftText := getFormatted(leftValue, Truncate)
 | 
						leftText := getFormatted(leftValue, Truncate)
 | 
				
			||||||
	rightType := getTypeName(rightValue)
 | 
						rightType := typeName(rightValue)
 | 
				
			||||||
	rightText := getFormatted(rightValue, Truncate)
 | 
						rightText := getFormatted(rightValue, Truncate)
 | 
				
			||||||
	return self.tk.Errorf(
 | 
						return self.tk.Errorf(
 | 
				
			||||||
		"left operand '%s' [%s] and right operand '%s' [%s] are not compatible with operator %q",
 | 
							"left operand '%s' [%s] and right operand '%s' [%s] are not compatible with operator %q",
 | 
				
			||||||
@ -175,8 +175,8 @@ func (self *term) errIncompatibleTypes(leftValue, rightValue any) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (self *term) errIncompatibleType(value any) error {
 | 
					func (self *term) errIncompatibleType(value any) error {
 | 
				
			||||||
	return self.tk.Errorf(
 | 
						return self.tk.Errorf(
 | 
				
			||||||
		"prefix/postfix operator %q do not support operand '%v' [%T]",
 | 
							"prefix/postfix operator %q do not support operand '%v' [%s]",
 | 
				
			||||||
		self.source(), value, value)
 | 
							self.source(), value, typeName(value))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *term) Errorf(template string, args ...any) (err error) {
 | 
					func (self *term) Errorf(template string, args ...any) (err error) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								utils.go
									
									
									
									
									
								
							@ -204,8 +204,10 @@ func CloneFilteredMap[K comparable, V any](source map[K]V, filter func(key K) (a
 | 
				
			|||||||
func toInt(value any, description string) (i int, err error) {
 | 
					func toInt(value any, description string) (i int, err error) {
 | 
				
			||||||
	if valueInt64, ok := value.(int64); ok {
 | 
						if valueInt64, ok := value.(int64); ok {
 | 
				
			||||||
		i = int(valueInt64)
 | 
							i = int(valueInt64)
 | 
				
			||||||
 | 
						} else if valueInt, ok := value.(int); ok {
 | 
				
			||||||
 | 
							i = valueInt
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		err = fmt.Errorf("%s expected integer, got %T (%v)", description, value, value)
 | 
							err = fmt.Errorf("%s expected integer, got %s (%v)", description, typeName(value), value)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user