Compare commits
	
		
			No commits in common. "e5f63c3d9d5d74f8a0b5db4057b94f8d18ee27cf" and "f22b5a6f0ba998b5dff9bc7b7f7c3ec1fd6b881b" have entirely different histories.
		
	
	
		
			e5f63c3d9d
			...
			f22b5a6f0b
		
	
		
@ -5,26 +5,7 @@
 | 
				
			|||||||
package expr
 | 
					package expr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	paramCount     = "count"
 | 
					 | 
				
			||||||
	paramItem      = "item"
 | 
					 | 
				
			||||||
	paramParts     = "parts"
 | 
						paramParts     = "parts"
 | 
				
			||||||
	paramSeparator = "separator"
 | 
						paramSeparator = "separator"
 | 
				
			||||||
	paramSource    = "source"
 | 
						paramSource    = "source"
 | 
				
			||||||
	paramSuffix    = "suffix"
 | 
					 | 
				
			||||||
	paramPrefix    = "prefix"
 | 
					 | 
				
			||||||
	paramStart     = "start"
 | 
					 | 
				
			||||||
	paramEnd       = "end"
 | 
					 | 
				
			||||||
	paramValue     = "value"
 | 
					 | 
				
			||||||
	paramEllipsis  = "..."
 | 
					 | 
				
			||||||
	typeFilepath   = "filepath"
 | 
					 | 
				
			||||||
	typeDirpath    = "dirpath"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					 | 
				
			||||||
// const (
 | 
					 | 
				
			||||||
// 	typeInteger  = "int"
 | 
					 | 
				
			||||||
// 	typeFloat    = "float"
 | 
					 | 
				
			||||||
// 	typeString   = "string"
 | 
					 | 
				
			||||||
// 	typeFraction = "fract"
 | 
					 | 
				
			||||||
// 	typeList     = "list"
 | 
					 | 
				
			||||||
// 	typeDict     = "dict"
 | 
					 | 
				
			||||||
// )
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -5,13 +5,10 @@
 | 
				
			|||||||
package expr
 | 
					package expr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	typeAny      = "any"
 | 
					 | 
				
			||||||
	typeBoolean  = "boolean"
 | 
						typeBoolean  = "boolean"
 | 
				
			||||||
	typeFloat    = "float"
 | 
						typeFloat    = "decimal"
 | 
				
			||||||
	typeFraction = "fraction"
 | 
						typeFraction = "fraction"
 | 
				
			||||||
	typeHandle   = "handle"
 | 
					 | 
				
			||||||
	typeInt      = "integer"
 | 
						typeInt      = "integer"
 | 
				
			||||||
	typeItem     = "item"
 | 
					 | 
				
			||||||
	typeNumber   = "number"
 | 
						typeNumber   = "number"
 | 
				
			||||||
	typeString   = "string"
 | 
						typeString   = "string"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
@ -22,9 +22,7 @@ func exportFunc(ctx ExprContext, name string, info ExprFunc) {
 | 
				
			|||||||
	if name[0] == '@' {
 | 
						if name[0] == '@' {
 | 
				
			||||||
		name = name[1:]
 | 
							name = name[1:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
 | 
						ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
 | 
				
			||||||
	// ctx.RegisterFuncInfo(name, info)
 | 
					 | 
				
			||||||
	ctx.RegisterFunc(name, info.Functor(), info.ReturnType(), info.Params())
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func exportObjects(destCtx, sourceCtx ExprContext) {
 | 
					func exportObjects(destCtx, sourceCtx ExprContext) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										25
									
								
								context.go
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								context.go
									
									
									
									
									
								
							@ -4,31 +4,28 @@
 | 
				
			|||||||
// context.go
 | 
					// context.go
 | 
				
			||||||
package expr
 | 
					package expr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ---- Function template
 | 
				
			||||||
 | 
					type FuncTemplate func(ctx ExprContext, name string, args []any) (result any, err error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ---- Functor interface
 | 
					// ---- Functor interface
 | 
				
			||||||
type Functor interface {
 | 
					type Functor interface {
 | 
				
			||||||
	Invoke(ctx ExprContext, name string, args []any) (result any, err error)
 | 
						Invoke(ctx ExprContext, name string, args []any) (result any, err error)
 | 
				
			||||||
	SetFunc(info ExprFunc)
 | 
					 | 
				
			||||||
	GetFunc() ExprFunc
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ---- Function Param Info
 | 
					type simpleFunctor struct {
 | 
				
			||||||
type ExprFuncParam interface {
 | 
						f FuncTemplate
 | 
				
			||||||
	Name() string
 | 
					}
 | 
				
			||||||
	Type() string
 | 
					
 | 
				
			||||||
	IsOptional() bool
 | 
					func (functor *simpleFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
				
			||||||
	IsRepeat() bool
 | 
						return functor.f(ctx, name, args)
 | 
				
			||||||
	DefaultValue() any
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ---- Function Info
 | 
					// ---- Function Info
 | 
				
			||||||
type ExprFunc interface {
 | 
					type ExprFunc interface {
 | 
				
			||||||
	Formatter
 | 
					 | 
				
			||||||
	Name() string
 | 
						Name() string
 | 
				
			||||||
	MinArgs() int
 | 
						MinArgs() int
 | 
				
			||||||
	MaxArgs() int
 | 
						MaxArgs() int
 | 
				
			||||||
	Functor() Functor
 | 
						Functor() Functor
 | 
				
			||||||
	Params() []ExprFuncParam
 | 
					 | 
				
			||||||
	ReturnType() string
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ----Expression Context
 | 
					// ----Expression Context
 | 
				
			||||||
@ -41,7 +38,5 @@ type ExprContext interface {
 | 
				
			|||||||
	EnumFuncs(func(name string) (accept bool)) (funcNames []string)
 | 
						EnumFuncs(func(name string) (accept bool)) (funcNames []string)
 | 
				
			||||||
	GetFuncInfo(name string) (item ExprFunc, exists bool)
 | 
						GetFuncInfo(name string) (item ExprFunc, exists bool)
 | 
				
			||||||
	Call(name string, args []any) (result any, err error)
 | 
						Call(name string, args []any) (result any, err error)
 | 
				
			||||||
	// RegisterFunc(name string, f Functor, minArgs, maxArgs int)
 | 
						RegisterFunc(name string, f Functor, minArgs, maxArgs int)
 | 
				
			||||||
	RegisterFuncInfo(info ExprFunc)
 | 
					 | 
				
			||||||
	RegisterFunc(name string, f Functor, returnType string, param []ExprFuncParam) error
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -42,7 +42,7 @@ func TestDictParser(t *testing.T) {
 | 
				
			|||||||
		var gotResult any
 | 
							var gotResult any
 | 
				
			||||||
		var gotErr error
 | 
							var gotErr error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ctx := NewSimpleStore()
 | 
							ctx := NewSimpleFuncStore()
 | 
				
			||||||
		ctx.SetVar("var1", int64(123))
 | 
							ctx.SetVar("var1", int64(123))
 | 
				
			||||||
		ctx.SetVar("var2", "abc")
 | 
							ctx.SetVar("var2", "abc")
 | 
				
			||||||
		ImportMathFuncs(ctx)
 | 
							ImportMathFuncs(ctx)
 | 
				
			||||||
 | 
				
			|||||||
@ -295,7 +295,7 @@ _item_ = _string-expr_ "**.**" _integer-expr_
 | 
				
			|||||||
=== Booleans
 | 
					=== Booleans
 | 
				
			||||||
Boolean data type has two values only: [blue]_true_ and [blue]_false_. Relational and boolean expressions result in boolean values.
 | 
					Boolean data type has two values only: [blue]_true_ and [blue]_false_. Relational and boolean expressions result in boolean values.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.Relational operators^(*)^
 | 
					.Relational operators
 | 
				
			||||||
[cols="^1,^2,6,4"]
 | 
					[cols="^1,^2,6,4"]
 | 
				
			||||||
|===
 | 
					|===
 | 
				
			||||||
| Symbol    | Operation     | Description               | Examples
 | 
					| Symbol    | Operation     | Description               | Examples
 | 
				
			||||||
@ -314,8 +314,6 @@ Boolean data type has two values only: [blue]_true_ and [blue]_false_. Relationa
 | 
				
			|||||||
[blue]`"b" \<= "b"` -> _true_
 | 
					[blue]`"b" \<= "b"` -> _true_
 | 
				
			||||||
|===
 | 
					|===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
^(*)^ See also the  [blue]`in` operator in the _list_ and _dictionary_ sections.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
.Boolean operators
 | 
					.Boolean operators
 | 
				
			||||||
[cols="^2,^2,5,4"]
 | 
					[cols="^2,^2,5,4"]
 | 
				
			||||||
@ -577,7 +575,7 @@ The table below shows all supported operators by decreasing priorities.
 | 
				
			|||||||
| Priority | Operators     | Position | Operation | Operands and results
 | 
					| Priority | Operators     | Position | Operation | Operands and results
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.2+|*ITEM*| [blue]`.` | _Infix_ | _List item_| _list_ `"."` _integer_ -> _any_
 | 
					.2+|*ITEM*| [blue]`.` | _Infix_ | _List item_| _list_ `"."` _integer_ -> _any_
 | 
				
			||||||
| [blue]`.` | _Infix_ | _Dict item_ | _dict_ `"."` _any_ -> _any_
 | 
					| [blue]`.` | _Infix_ | _Dict item_ | _dict_ `""` _any_ -> _any_
 | 
				
			||||||
.2+|*INC*| [blue]`++` | _Postfix_ | _Post increment_| _integer-variable_ `"++"` -> _integer_
 | 
					.2+|*INC*| [blue]`++` | _Postfix_ | _Post increment_| _integer-variable_ `"++"` -> _integer_
 | 
				
			||||||
| [blue]`++` | _Postfix_ | _Next item_ | _iterator_ `"++"` -> _any_
 | 
					| [blue]`++` | _Postfix_ | _Next item_ | _iterator_ `"++"` -> _any_
 | 
				
			||||||
.1+|*FACT*| [blue]`!` | _Postfix_ | _Factorial_| _integer_ `"!"` -> _integer_
 | 
					.1+|*FACT*| [blue]`!` | _Postfix_ | _Factorial_| _integer_ `"!"` -> _integer_
 | 
				
			||||||
 | 
				
			|||||||
@ -585,7 +585,7 @@ pre.rouge .ss {
 | 
				
			|||||||
<div class="sectionbody">
 | 
					<div class="sectionbody">
 | 
				
			||||||
<!-- toc disabled -->
 | 
					<!-- toc disabled -->
 | 
				
			||||||
<div class="paragraph">
 | 
					<div class="paragraph">
 | 
				
			||||||
<p><mark>TODO: Work in progress (last update on 2024/05/20, 06:58 a.m.)</mark></p>
 | 
					<p><mark>TODO: Work in progress (last update on 2024/05/17, 15:47 p.m.)</mark></p>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
@ -1041,7 +1041,7 @@ pre.rouge .ss {
 | 
				
			|||||||
<p>Boolean data type has two values only: <em class="blue">true</em> and <em class="blue">false</em>. Relational and boolean expressions result in boolean values.</p>
 | 
					<p>Boolean data type has two values only: <em class="blue">true</em> and <em class="blue">false</em>. Relational and boolean expressions result in boolean values.</p>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
<table class="tableblock frame-all grid-all stretch">
 | 
					<table class="tableblock frame-all grid-all stretch">
 | 
				
			||||||
<caption class="title">Table 4. Relational operators<sup>(*)</sup></caption>
 | 
					<caption class="title">Table 4. Relational operators</caption>
 | 
				
			||||||
<colgroup>
 | 
					<colgroup>
 | 
				
			||||||
<col style="width: 7.6923%;">
 | 
					<col style="width: 7.6923%;">
 | 
				
			||||||
<col style="width: 15.3846%;">
 | 
					<col style="width: 15.3846%;">
 | 
				
			||||||
@ -1101,9 +1101,6 @@ pre.rouge .ss {
 | 
				
			|||||||
</tr>
 | 
					</tr>
 | 
				
			||||||
</tbody>
 | 
					</tbody>
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
<div class="paragraph">
 | 
					 | 
				
			||||||
<p><sup>(*)</sup> See also the  <code class="blue">in</code> operator in the <em>list</em> and <em>dictionary</em> sections.</p>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
<table class="tableblock frame-all grid-all stretch">
 | 
					<table class="tableblock frame-all grid-all stretch">
 | 
				
			||||||
<caption class="title">Table 5. Boolean operators</caption>
 | 
					<caption class="title">Table 5. Boolean operators</caption>
 | 
				
			||||||
<colgroup>
 | 
					<colgroup>
 | 
				
			||||||
@ -1874,7 +1871,7 @@ These operators have a high priority, in particular higher than the operator <co
 | 
				
			|||||||
</div>
 | 
					</div>
 | 
				
			||||||
<div id="footer">
 | 
					<div id="footer">
 | 
				
			||||||
<div id="footer-text">
 | 
					<div id="footer-text">
 | 
				
			||||||
Last updated 2024-05-20 09:40:23 +0200
 | 
					Last updated 2024-05-20 06:58:09 +0200
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
 | 
				
			|||||||
@ -44,7 +44,7 @@ func TestExpr(t *testing.T) {
 | 
				
			|||||||
		var gotResult any
 | 
							var gotResult any
 | 
				
			||||||
		var gotErr error
 | 
							var gotErr error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ctx := NewSimpleStore()
 | 
							ctx := NewSimpleFuncStore()
 | 
				
			||||||
		// ImportMathFuncs(ctx)
 | 
							// ImportMathFuncs(ctx)
 | 
				
			||||||
		// ImportImportFunc(ctx)
 | 
							// ImportImportFunc(ctx)
 | 
				
			||||||
		ImportOsFuncs(ctx)
 | 
							ImportOsFuncs(ctx)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										67
									
								
								func-base.go
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								func-base.go
									
									
									
									
									
								
							@ -54,24 +54,6 @@ func isDictionaryFunc(ctx ExprContext, name string, args []any) (result any, err
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func boolFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
					 | 
				
			||||||
	switch v := args[0].(type) {
 | 
					 | 
				
			||||||
	case int64:
 | 
					 | 
				
			||||||
		result = (v != 0)
 | 
					 | 
				
			||||||
	case *fraction:
 | 
					 | 
				
			||||||
		result = v.num != 0
 | 
					 | 
				
			||||||
	case float64:
 | 
					 | 
				
			||||||
		result = v != 0.0
 | 
					 | 
				
			||||||
	case bool:
 | 
					 | 
				
			||||||
		result = v
 | 
					 | 
				
			||||||
	case string:
 | 
					 | 
				
			||||||
		result = len(v) > 0
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		err = errCantConvert(name, v, "bool")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func intFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
					func intFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
				
			||||||
	switch v := args[0].(type) {
 | 
						switch v := args[0].(type) {
 | 
				
			||||||
	case int64:
 | 
						case int64:
 | 
				
			||||||
@ -137,6 +119,10 @@ func fractFunc(ctx ExprContext, name string, args []any) (result any, err error)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	case float64:
 | 
						case float64:
 | 
				
			||||||
		result, err = float64ToFraction(v)
 | 
							result, err = float64ToFraction(v)
 | 
				
			||||||
 | 
							// var n, d int64
 | 
				
			||||||
 | 
							// if n, d, err = float64ToFraction(v); err == nil {
 | 
				
			||||||
 | 
							//	result = newFraction(n, d)
 | 
				
			||||||
 | 
							// }
 | 
				
			||||||
	case bool:
 | 
						case bool:
 | 
				
			||||||
		if v {
 | 
							if v {
 | 
				
			||||||
			result = newFraction(1, 1)
 | 
								result = newFraction(1, 1)
 | 
				
			||||||
@ -145,6 +131,16 @@ func fractFunc(ctx ExprContext, name string, args []any) (result any, err error)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	case string:
 | 
						case string:
 | 
				
			||||||
		result, err = makeGeneratingFraction(v)
 | 
							result, err = makeGeneratingFraction(v)
 | 
				
			||||||
 | 
							// var f float64
 | 
				
			||||||
 | 
							// // TODO temporary implementation
 | 
				
			||||||
 | 
							// if f, err = strconv.ParseFloat(v, 64); err == nil {
 | 
				
			||||||
 | 
							// 	var n, d int64
 | 
				
			||||||
 | 
							// 	if n, d, err = float64ToFraction(f); err == nil {
 | 
				
			||||||
 | 
							// 		result = newFraction(n, d)
 | 
				
			||||||
 | 
							// 	}
 | 
				
			||||||
 | 
							// } else {
 | 
				
			||||||
 | 
							// 	errors.New("convertion from string to float is ongoing")
 | 
				
			||||||
 | 
							// }
 | 
				
			||||||
	case *fraction:
 | 
						case *fraction:
 | 
				
			||||||
		result = v
 | 
							result = v
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@ -158,27 +154,20 @@ func iteratorFunc(ctx ExprContext, name string, args []any) (result any, err err
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ImportBuiltinsFuncs(ctx ExprContext) {
 | 
					func ImportBuiltinsFuncs(ctx ExprContext) {
 | 
				
			||||||
	anyParams := []ExprFuncParam{
 | 
						ctx.RegisterFunc("isNil", &simpleFunctor{f: isNilFunc}, 1, 1)
 | 
				
			||||||
		newFuncParam(paramValue),
 | 
						ctx.RegisterFunc("isInt", &simpleFunctor{f: isIntFunc}, 1, 1)
 | 
				
			||||||
	}
 | 
						ctx.RegisterFunc("isFloat", &simpleFunctor{f: isFloatFunc}, 1, 1)
 | 
				
			||||||
 | 
						ctx.RegisterFunc("isBool", &simpleFunctor{f: isBoolFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("isNil", newGolangFunctor(isNilFunc), typeBoolean, anyParams)
 | 
						ctx.RegisterFunc("isString", &simpleFunctor{f: isStringFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("isInt", newGolangFunctor(isIntFunc), typeBoolean, anyParams)
 | 
						ctx.RegisterFunc("isFraction", &simpleFunctor{f: isFractionFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("isFloat", newGolangFunctor(isFloatFunc), typeBoolean, anyParams)
 | 
						ctx.RegisterFunc("isFract", &simpleFunctor{f: isFractionFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("isBool", newGolangFunctor(isBoolFunc), typeBoolean, anyParams)
 | 
						ctx.RegisterFunc("isRational", &simpleFunctor{f: isRationalFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("isString", newGolangFunctor(isStringFunc), typeBoolean, anyParams)
 | 
						ctx.RegisterFunc("isList", &simpleFunctor{f: isListFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("isFract", newGolangFunctor(isFractionFunc), typeBoolean, anyParams)
 | 
						ctx.RegisterFunc("isDictionary", &simpleFunctor{f: isDictionaryFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("isRational", newGolangFunctor(isRationalFunc), typeBoolean, anyParams)
 | 
						ctx.RegisterFunc("isDict", &simpleFunctor{f: isDictionaryFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("isList", newGolangFunctor(isListFunc), typeBoolean, anyParams)
 | 
						ctx.RegisterFunc("int", &simpleFunctor{f: intFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("isDict", newGolangFunctor(isDictionaryFunc), typeBoolean, anyParams)
 | 
						ctx.RegisterFunc("dec", &simpleFunctor{f: decFunc}, 1, 1)
 | 
				
			||||||
 | 
						ctx.RegisterFunc("fract", &simpleFunctor{f: fractFunc}, 1, 2)
 | 
				
			||||||
	ctx.RegisterFunc("bool", newGolangFunctor(boolFunc), typeBoolean, anyParams)
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("int", newGolangFunctor(intFunc), typeInt, anyParams)
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("dec", newGolangFunctor(decFunc), typeFloat, anyParams)
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("fract", newGolangFunctor(fractFunc), typeFraction, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParam(paramValue),
 | 
					 | 
				
			||||||
		newFuncParamFlagDef("denominator", pfOptional, 1),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
 | 
				
			|||||||
@ -137,12 +137,8 @@ func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (resu
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ImportImportFuncs(ctx ExprContext) {
 | 
					func ImportImportFuncs(ctx ExprContext) {
 | 
				
			||||||
	ctx.RegisterFunc("import", newGolangFunctor(importFunc), typeAny, []ExprFuncParam{
 | 
						ctx.RegisterFunc("import", &simpleFunctor{f: importFunc}, 1, -1)
 | 
				
			||||||
		newFuncParamFlag(typeFilepath, pfRepeat),
 | 
						ctx.RegisterFunc("importAll", &simpleFunctor{f: importAllFunc}, 1, -1)
 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("importAll", newGolangFunctor(importAllFunc), typeAny, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParamFlag(typeFilepath, pfRepeat),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
 | 
				
			|||||||
@ -167,13 +167,8 @@ func mulFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ImportMathFuncs(ctx ExprContext) {
 | 
					func ImportMathFuncs(ctx ExprContext) {
 | 
				
			||||||
	ctx.RegisterFunc("add", &golangFunctor{f: addFunc}, typeNumber, []ExprFuncParam{
 | 
						ctx.RegisterFunc("add", &simpleFunctor{f: addFunc}, 0, -1)
 | 
				
			||||||
		newFuncParamFlagDef(paramValue, pfOptional|pfRepeat, 0),
 | 
						ctx.RegisterFunc("mul", &simpleFunctor{f: mulFunc}, 0, -1)
 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("mul", &golangFunctor{f: mulFunc}, typeNumber, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParamFlagDef(paramValue, pfOptional|pfRepeat, 1),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										26
									
								
								func-os.go
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								func-os.go
									
									
									
									
									
								
							@ -158,26 +158,12 @@ func readFileFunc(ctx ExprContext, name string, args []any) (result any, err err
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ImportOsFuncs(ctx ExprContext) {
 | 
					func ImportOsFuncs(ctx ExprContext) {
 | 
				
			||||||
	ctx.RegisterFunc("openFile", newGolangFunctor(openFileFunc), typeHandle, []ExprFuncParam{
 | 
						ctx.RegisterFunc("openFile", &simpleFunctor{f: openFileFunc}, 1, 1)
 | 
				
			||||||
		newFuncParam(typeFilepath),
 | 
						ctx.RegisterFunc("appendFile", &simpleFunctor{f: appendFileFunc}, 1, 1)
 | 
				
			||||||
	})
 | 
						ctx.RegisterFunc("createFile", &simpleFunctor{f: createFileFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("appendFile", newGolangFunctor(appendFileFunc), typeHandle, []ExprFuncParam{
 | 
						ctx.RegisterFunc("writeFile", &simpleFunctor{f: writeFileFunc}, 1, -1)
 | 
				
			||||||
		newFuncParam(typeFilepath),
 | 
						ctx.RegisterFunc("readFile", &simpleFunctor{f: readFileFunc}, 1, 2)
 | 
				
			||||||
	})
 | 
						ctx.RegisterFunc("closeFile", &simpleFunctor{f: closeFileFunc}, 1, 1)
 | 
				
			||||||
	ctx.RegisterFunc("createFile", newGolangFunctor(createFileFunc), typeHandle, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParam(typeFilepath),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("writeFile", newGolangFunctor(writeFileFunc), typeInt, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParam(typeHandle),
 | 
					 | 
				
			||||||
		newFuncParamFlagDef(typeItem, pfOptional|pfRepeat, ""),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("readFile", newGolangFunctor(readFileFunc), typeString, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParam(typeHandle),
 | 
					 | 
				
			||||||
		newFuncParamFlagDef("limitCh", pfOptional, "\\n"),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("closeFile", newGolangFunctor(closeFileFunc), typeBoolean, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParam(typeHandle),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
 | 
				
			|||||||
@ -33,9 +33,9 @@ func doJoinStr(funcName string, sep string, it Iterator) (result any, err error)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func joinStrFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
					func joinStrFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
				
			||||||
	//	if len(args) < 1 {
 | 
					//	if len(args) < 1 {
 | 
				
			||||||
	//		return nil, errMissingRequiredParameter(name, paramSeparator)
 | 
					//		return nil, errMissingRequiredParameter(name, paramSeparator)
 | 
				
			||||||
	//	}
 | 
					//	}
 | 
				
			||||||
	if sep, ok := args[0].(string); ok {
 | 
						if sep, ok := args[0].(string); ok {
 | 
				
			||||||
		if len(args) == 1 {
 | 
							if len(args) == 1 {
 | 
				
			||||||
			result = ""
 | 
								result = ""
 | 
				
			||||||
@ -62,6 +62,9 @@ func subStrFunc(ctx ExprContext, name string, args []any) (result any, err error
 | 
				
			|||||||
	var source string
 | 
						var source string
 | 
				
			||||||
	var ok bool
 | 
						var ok bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//	if len(args) < 1 {
 | 
				
			||||||
 | 
					//		return nil, errMissingRequiredParameter(name, paramSource)
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
	if source, ok = args[0].(string); !ok {
 | 
						if source, ok = args[0].(string); !ok {
 | 
				
			||||||
		return nil, errWrongParamType(name, paramSource, typeString, args[0])
 | 
							return nil, errWrongParamType(name, paramSource, typeString, args[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -90,6 +93,9 @@ func trimStrFunc(ctx ExprContext, name string, args []any) (result any, err erro
 | 
				
			|||||||
	var source string
 | 
						var source string
 | 
				
			||||||
	var ok bool
 | 
						var ok bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//	if len(args) < 1 {
 | 
				
			||||||
 | 
					//		return nil, errMissingRequiredParameter(name, paramSource)
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
	if source, ok = args[0].(string); !ok {
 | 
						if source, ok = args[0].(string); !ok {
 | 
				
			||||||
		return nil, errWrongParamType(name, paramSource, typeString, args[0])
 | 
							return nil, errWrongParamType(name, paramSource, typeString, args[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -102,7 +108,9 @@ func startsWithStrFunc(ctx ExprContext, name string, args []any) (result any, er
 | 
				
			|||||||
	var ok bool
 | 
						var ok bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result = false
 | 
						result = false
 | 
				
			||||||
 | 
					//	if len(args) < 1 {
 | 
				
			||||||
 | 
					//		return result, errMissingRequiredParameter(name, paramSource)
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
	if source, ok = args[0].(string); !ok {
 | 
						if source, ok = args[0].(string); !ok {
 | 
				
			||||||
		return result, errWrongParamType(name, paramSource, typeString, args[0])
 | 
							return result, errWrongParamType(name, paramSource, typeString, args[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -125,7 +133,9 @@ func endsWithStrFunc(ctx ExprContext, name string, args []any) (result any, err
 | 
				
			|||||||
	var ok bool
 | 
						var ok bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result = false
 | 
						result = false
 | 
				
			||||||
 | 
					//	if len(args) < 1 {
 | 
				
			||||||
 | 
					//		return result, errMissingRequiredParameter(name, paramSource)
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
	if source, ok = args[0].(string); !ok {
 | 
						if source, ok = args[0].(string); !ok {
 | 
				
			||||||
		return result, errWrongParamType(name, paramSource, typeString, args[0])
 | 
							return result, errWrongParamType(name, paramSource, typeString, args[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -149,6 +159,9 @@ func splitStrFunc(ctx ExprContext, name string, args []any) (result any, err err
 | 
				
			|||||||
	var parts []string
 | 
						var parts []string
 | 
				
			||||||
	var ok bool
 | 
						var ok bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//	if len(args) < 1 {
 | 
				
			||||||
 | 
					//		return result, errMissingRequiredParameter(name, paramSource)
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
	if source, ok = args[0].(string); !ok {
 | 
						if source, ok = args[0].(string); !ok {
 | 
				
			||||||
		return result, errWrongParamType(name, paramSource, typeString, args[0])
 | 
							return result, errWrongParamType(name, paramSource, typeString, args[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -183,36 +196,12 @@ func splitStrFunc(ctx ExprContext, name string, args []any) (result any, err err
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Import above functions in the context
 | 
					// Import above functions in the context
 | 
				
			||||||
func ImportStringFuncs(ctx ExprContext) {
 | 
					func ImportStringFuncs(ctx ExprContext) {
 | 
				
			||||||
	ctx.RegisterFunc("joinStr", newGolangFunctor(joinStrFunc), typeString, []ExprFuncParam{
 | 
						ctx.RegisterFunc("joinStr", &simpleFunctor{f: joinStrFunc}, 1, -1)
 | 
				
			||||||
		newFuncParam(paramSeparator),
 | 
						ctx.RegisterFunc("subStr", &simpleFunctor{f: subStrFunc}, 1, -1)
 | 
				
			||||||
		newFuncParamFlagDef(paramItem, pfOptional|pfRepeat, ""),
 | 
						ctx.RegisterFunc("splitStr", &simpleFunctor{f: splitStrFunc}, 2, -1)
 | 
				
			||||||
	})
 | 
						ctx.RegisterFunc("trimStr", &simpleFunctor{f: trimStrFunc}, 1, -1)
 | 
				
			||||||
 | 
						ctx.RegisterFunc("startsWithStr", &simpleFunctor{f: startsWithStrFunc}, 2, -1)
 | 
				
			||||||
	ctx.RegisterFunc("subStr", newGolangFunctor(subStrFunc), typeString, []ExprFuncParam{
 | 
						ctx.RegisterFunc("endsWithStr", &simpleFunctor{f: endsWithStrFunc}, 2, -1)
 | 
				
			||||||
		newFuncParam(paramSource),
 | 
					 | 
				
			||||||
		newFuncParamFlagDef(paramStart, pfOptional, 0),
 | 
					 | 
				
			||||||
		newFuncParamFlagDef(paramCount, pfOptional, -1),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("splitStr", newGolangFunctor(splitStrFunc), "list of "+typeString, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParam(paramSource),
 | 
					 | 
				
			||||||
		newFuncParamFlagDef(paramSeparator, pfOptional, ""),
 | 
					 | 
				
			||||||
		newFuncParamFlagDef(paramCount, pfOptional, -1),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("trimStr", newGolangFunctor(trimStrFunc), typeString, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParam(paramSource),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("startsWithStr", newGolangFunctor(startsWithStrFunc), typeBoolean, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParam(paramSource),
 | 
					 | 
				
			||||||
		newFuncParamFlag(paramPrefix, pfRepeat),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.RegisterFunc("endsWithStr", newGolangFunctor(endsWithStrFunc), typeBoolean, []ExprFuncParam{
 | 
					 | 
				
			||||||
		newFuncParam(paramSource),
 | 
					 | 
				
			||||||
		newFuncParamFlag(paramSuffix, pfRepeat),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Register the import function in the import-register.
 | 
					// Register the import function in the import-register.
 | 
				
			||||||
 | 
				
			|||||||
@ -76,41 +76,14 @@ func TestFuncs(t *testing.T) {
 | 
				
			|||||||
		/*  63 */ {`dec(true)`, float64(1), nil},
 | 
							/*  63 */ {`dec(true)`, float64(1), nil},
 | 
				
			||||||
		/*  64 */ {`dec(true")`, nil, errors.New("[1:11] missing string termination \"")},
 | 
							/*  64 */ {`dec(true")`, nil, errors.New("[1:11] missing string termination \"")},
 | 
				
			||||||
		/*  65 */ {`builtin "string"; joinStr("-", [1, "two", "three"])`, nil, errors.New(`joinStr() expected string, got int64 (1)`)},
 | 
							/*  65 */ {`builtin "string"; joinStr("-", [1, "two", "three"])`, nil, errors.New(`joinStr() expected string, got int64 (1)`)},
 | 
				
			||||||
		/*  66 */ {`dec()`, nil, errors.New(`too few params -- expected 1, got 0`)},
 | 
							/*  65 */ {`dec()`, nil, errors.New(`too few params -- expected 1, got 0`)},
 | 
				
			||||||
		/*  67 */ {`dec(1,2,3)`, nil, errors.New(`too much params -- expected 1, got 3`)},
 | 
							/*  66 */ {`dec(1,2,3)`, nil, errors.New(`too much params -- expected 1, got 3`)},
 | 
				
			||||||
		/*  68 */ {`builtin "string"; joinStr()`, nil, errors.New(`too few params -- expected 1 or more, got 0`)},
 | 
							/*  67 */ {`builtin "string"; joinStr()`, nil, errors.New(`too few params -- expected 1 or more, got 0`)},
 | 
				
			||||||
		/*  69 */ /*{`builtin "string"; $$global`, `vars: {
 | 
							// /*  64 */ {`string(true)`, "true", nil},
 | 
				
			||||||
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		funcs: {
 | 
					 | 
				
			||||||
		    	add(any=0 ...) -> number,
 | 
					 | 
				
			||||||
		    	dec(any) -> decimal,
 | 
					 | 
				
			||||||
		    	endsWithStr(source, suffix) -> boolean,
 | 
					 | 
				
			||||||
		    	fract(any, denominator=1) -> fraction,
 | 
					 | 
				
			||||||
		    	import( ...) -> any,
 | 
					 | 
				
			||||||
		    	importAll( ...) -> any,
 | 
					 | 
				
			||||||
		    	int(any) -> integer,
 | 
					 | 
				
			||||||
		    	isBool(any) -> boolean,
 | 
					 | 
				
			||||||
		    	isDec(any) -> boolean,
 | 
					 | 
				
			||||||
		    	isDict(any) -> boolean,
 | 
					 | 
				
			||||||
		    	isFloat(any) -> boolean,
 | 
					 | 
				
			||||||
		    	isFract(any) -> boolean,
 | 
					 | 
				
			||||||
		    	isInt(any) -> boolean,
 | 
					 | 
				
			||||||
		    	isList(any) -> boolean,
 | 
					 | 
				
			||||||
		    	isNil(any) -> boolean,
 | 
					 | 
				
			||||||
		    	isString(any) -> boolean,
 | 
					 | 
				
			||||||
		    	joinStr(separator, item="" ...) -> string,
 | 
					 | 
				
			||||||
		    	mul(any=1 ...) -> number,
 | 
					 | 
				
			||||||
		    	splitStr(source, separator="", count=-1) -> list of string,
 | 
					 | 
				
			||||||
		    	startsWithStr(source, prefix) -> boolean,
 | 
					 | 
				
			||||||
		    	subStr(source, start=0, count=-1) -> string,
 | 
					 | 
				
			||||||
		    	trimStr(source) -> string
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		`, nil},*/
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Setenv("EXPR_PATH", ".")
 | 
						t.Setenv("EXPR_PATH", ".")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// parserTestSpec(t, "Func", inputs, 69)
 | 
						//parserTest(t, "Func", inputs[54:55])
 | 
				
			||||||
	parserTest(t, "Func", inputs)
 | 
						parserTest(t, "Func", inputs)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										232
									
								
								function.go
									
									
									
									
									
								
							
							
						
						
									
										232
									
								
								function.go
									
									
									
									
									
								
							@ -1,232 +0,0 @@
 | 
				
			|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 | 
					 | 
				
			||||||
// All rights reserved.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// function.go
 | 
					 | 
				
			||||||
package expr
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ---- Function template
 | 
					 | 
				
			||||||
type FuncTemplate func(ctx ExprContext, name string, args []any) (result any, err error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ---- Common functor definition
 | 
					 | 
				
			||||||
type baseFunctor struct {
 | 
					 | 
				
			||||||
	info ExprFunc
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (functor *baseFunctor) ToString(opt FmtOpt) (s string) {
 | 
					 | 
				
			||||||
	if functor.info != nil {
 | 
					 | 
				
			||||||
		s = functor.info.ToString(opt)
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		s = "func() {<body>}"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return s
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (functor *baseFunctor) SetFunc(info ExprFunc) {
 | 
					 | 
				
			||||||
	functor.info = info
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (functor *baseFunctor) GetFunc() ExprFunc {
 | 
					 | 
				
			||||||
	return functor.info
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ---- Linking with the functions of Go
 | 
					 | 
				
			||||||
type golangFunctor struct {
 | 
					 | 
				
			||||||
	baseFunctor
 | 
					 | 
				
			||||||
	f FuncTemplate
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newGolangFunctor(f FuncTemplate) *golangFunctor {
 | 
					 | 
				
			||||||
	return &golangFunctor{f: f}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (functor *golangFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
					 | 
				
			||||||
	return functor.f(ctx, name, args)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ---- Linking with the functions of Expr
 | 
					 | 
				
			||||||
type exprFunctor struct {
 | 
					 | 
				
			||||||
	baseFunctor
 | 
					 | 
				
			||||||
	params []string
 | 
					 | 
				
			||||||
	expr   Expr
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newExprFunctor(e Expr, params []string) *exprFunctor {
 | 
					 | 
				
			||||||
	return &exprFunctor{expr: e, params: params}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
					 | 
				
			||||||
	for i, p := range functor.params {
 | 
					 | 
				
			||||||
		if i < len(args) {
 | 
					 | 
				
			||||||
			arg := args[i]
 | 
					 | 
				
			||||||
			if funcArg, ok := arg.(Functor); ok {
 | 
					 | 
				
			||||||
				// ctx.RegisterFunc(p, functor, 0, -1)
 | 
					 | 
				
			||||||
				ctx.RegisterFunc(p, funcArg, typeAny, []ExprFuncParam{
 | 
					 | 
				
			||||||
					newFuncParam(paramValue),
 | 
					 | 
				
			||||||
				})
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				ctx.UnsafeSetVar(p, arg)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			ctx.UnsafeSetVar(p, nil)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	result, err = functor.expr.eval(ctx, false)
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ---- Function Parameters
 | 
					 | 
				
			||||||
type paramFlags uint16
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	pfOptional paramFlags = 1 << iota
 | 
					 | 
				
			||||||
	pfRepeat
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type funcParamInfo struct {
 | 
					 | 
				
			||||||
	name         string
 | 
					 | 
				
			||||||
	flags        paramFlags
 | 
					 | 
				
			||||||
	defaultValue any
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newFuncParam(name string) ExprFuncParam {
 | 
					 | 
				
			||||||
	return &funcParamInfo{name: name}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newFuncParamFlag(name string, flags paramFlags) ExprFuncParam {
 | 
					 | 
				
			||||||
	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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// --- Functions
 | 
					 | 
				
			||||||
type funcInfo struct {
 | 
					 | 
				
			||||||
	name       string
 | 
					 | 
				
			||||||
	minArgs    int
 | 
					 | 
				
			||||||
	maxArgs    int
 | 
					 | 
				
			||||||
	functor    Functor
 | 
					 | 
				
			||||||
	params     []ExprFuncParam
 | 
					 | 
				
			||||||
	returnType string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newFuncInfo(name string, functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) {
 | 
					 | 
				
			||||||
	var minArgs = 0
 | 
					 | 
				
			||||||
	var maxArgs = 0
 | 
					 | 
				
			||||||
	if params != nil {
 | 
					 | 
				
			||||||
		for _, p := range params {
 | 
					 | 
				
			||||||
			if maxArgs == -1 {
 | 
					 | 
				
			||||||
				return nil, fmt.Errorf("no more params can be specified after the ellipsis symbol: %q", p.Name())
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if p.IsOptional() {
 | 
					 | 
				
			||||||
				maxArgs++
 | 
					 | 
				
			||||||
			} else if maxArgs == minArgs {
 | 
					 | 
				
			||||||
				minArgs++
 | 
					 | 
				
			||||||
				maxArgs++
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				return nil, fmt.Errorf("can't specify non-optional param after optional ones: %q", p.Name())
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if p.IsRepeat() {
 | 
					 | 
				
			||||||
				maxArgs = -1
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	info = &funcInfo{
 | 
					 | 
				
			||||||
		name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, params: params,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	functor.SetFunc(info)
 | 
					 | 
				
			||||||
	return info, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newUnnamedFuncInfo(functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) {
 | 
					 | 
				
			||||||
	return newFuncInfo("unnamed", functor, returnType, params)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
	if len(info.Name()) == 0 {
 | 
					 | 
				
			||||||
		sb.WriteString("func")
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		sb.WriteString(info.Name())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	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)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sb.WriteString(" {<body>}")
 | 
					 | 
				
			||||||
	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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -6,7 +6,7 @@ package expr
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "path/filepath"
 | 
					import "path/filepath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var globalCtx *SimpleStore
 | 
					var globalCtx *SimpleFuncStore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ImportInContext(name string) (exists bool) {
 | 
					func ImportInContext(name string) (exists bool) {
 | 
				
			||||||
	var mod *module
 | 
						var mod *module
 | 
				
			||||||
@ -50,6 +50,5 @@ func GetFuncInfo(ctx ExprContext, name string) (item ExprFunc, exists bool, owne
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	globalCtx = NewSimpleStore()
 | 
						globalCtx = NewSimpleFuncStore()
 | 
				
			||||||
	ImportBuiltinsFuncs(globalCtx)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -34,15 +34,12 @@ func EvalStringA(source string, args ...Arg) (result any, err error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func EvalStringV(source string, args []Arg) (result any, err error) {
 | 
					func EvalStringV(source string, args []Arg) (result any, err error) {
 | 
				
			||||||
	ctx := NewSimpleStore()
 | 
						ctx := NewSimpleFuncStore()
 | 
				
			||||||
	for _, arg := range args {
 | 
						for _, arg := range args {
 | 
				
			||||||
		if isFunc(arg.Value) {
 | 
							if isFunc(arg.Value) {
 | 
				
			||||||
			if f, ok := arg.Value.(FuncTemplate); ok {
 | 
								if f, ok := arg.Value.(FuncTemplate); ok {
 | 
				
			||||||
				functor := newGolangFunctor(f)
 | 
									functor := &simpleFunctor{f: f}
 | 
				
			||||||
				// ctx.RegisterFunc(arg.Name, functor, 0, -1)
 | 
									ctx.RegisterFunc(arg.Name, functor, 0, -1)
 | 
				
			||||||
				ctx.RegisterFunc(arg.Name, functor, typeAny, []ExprFuncParam{
 | 
					 | 
				
			||||||
					newFuncParamFlagDef(paramValue, pfOptional|pfRepeat, 0),
 | 
					 | 
				
			||||||
				})
 | 
					 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				err = fmt.Errorf("invalid function specification: %q", arg.Name)
 | 
									err = fmt.Errorf("invalid function specification: %q", arg.Name)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
				
			|||||||
@ -52,7 +52,7 @@ func TestEvalStringA(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestEvalString(t *testing.T) {
 | 
					func TestEvalString(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx := NewSimpleStore()
 | 
						ctx := NewSimpleVarStore()
 | 
				
			||||||
	ctx.SetVar("a", uint8(1))
 | 
						ctx.SetVar("a", uint8(1))
 | 
				
			||||||
	ctx.SetVar("b", int8(2))
 | 
						ctx.SetVar("b", int8(2))
 | 
				
			||||||
	ctx.SetVar("f", 2.0)
 | 
						ctx.SetVar("f", 2.0)
 | 
				
			||||||
 | 
				
			|||||||
@ -60,7 +60,7 @@ func TestListParser(t *testing.T) {
 | 
				
			|||||||
		var gotResult any
 | 
							var gotResult any
 | 
				
			||||||
		var gotErr error
 | 
							var gotErr error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ctx := NewSimpleStore()
 | 
							ctx := NewSimpleFuncStore()
 | 
				
			||||||
		// ctx.SetVar("var1", int64(123))
 | 
							// ctx.SetVar("var1", int64(123))
 | 
				
			||||||
		// ctx.SetVar("var2", "abc")
 | 
							// ctx.SetVar("var2", "abc")
 | 
				
			||||||
		ImportMathFuncs(ctx)
 | 
							ImportMathFuncs(ctx)
 | 
				
			||||||
 | 
				
			|||||||
@ -31,8 +31,7 @@ func checkFunctionCall(ctx ExprContext, name string, params []any) (err error) {
 | 
				
			|||||||
			err = errTooMuchParams(info.MaxArgs(), len(params))
 | 
								err = errTooMuchParams(info.MaxArgs(), len(params))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err == nil && owner != ctx {
 | 
							if err == nil && owner != ctx {
 | 
				
			||||||
			// ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
 | 
								ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
 | 
				
			||||||
			ctx.RegisterFuncInfo(info)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		err = fmt.Errorf("unknown function %s()", name)
 | 
							err = fmt.Errorf("unknown function %s()", name)
 | 
				
			||||||
@ -76,30 +75,27 @@ func newFuncDefTerm(tk *Token, args []*term) *term {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// -------- eval func def
 | 
					// -------- eval func def
 | 
				
			||||||
// TODO
 | 
					// TODO
 | 
				
			||||||
// type funcDefFunctor struct {
 | 
					type funcDefFunctor struct {
 | 
				
			||||||
// 	params []string
 | 
						params []string
 | 
				
			||||||
// 	expr   Expr
 | 
						expr   Expr
 | 
				
			||||||
// }
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// func (funcDef *funcDefFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
					func (functor *funcDefFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
				
			||||||
// 	for i, p := range funcDef.params {
 | 
						for i, p := range functor.params {
 | 
				
			||||||
// 		if i < len(args) {
 | 
							if i < len(args) {
 | 
				
			||||||
// 			arg := args[i]
 | 
								arg := args[i]
 | 
				
			||||||
// 			if functor, ok := arg.(Functor); ok {
 | 
								if functor, ok := arg.(Functor); ok {
 | 
				
			||||||
// 				// ctx.RegisterFunc(p, functor, 0, -1)
 | 
									ctx.RegisterFunc(p, functor, 0, -1)
 | 
				
			||||||
// 				ctx.RegisterFunc2(p, functor, typeAny, []ExprFuncParam{
 | 
								} else {
 | 
				
			||||||
// 					newFuncParam(paramValue),
 | 
									ctx.UnsafeSetVar(p, arg)
 | 
				
			||||||
// 				})
 | 
								}
 | 
				
			||||||
// 			} else {
 | 
							} else {
 | 
				
			||||||
// 				ctx.UnsafeSetVar(p, arg)
 | 
								ctx.UnsafeSetVar(p, nil)
 | 
				
			||||||
// 			}
 | 
							}
 | 
				
			||||||
// 		} else {
 | 
						}
 | 
				
			||||||
// 			ctx.UnsafeSetVar(p, nil)
 | 
						result, err = functor.expr.eval(ctx, false)
 | 
				
			||||||
// 		}
 | 
						return
 | 
				
			||||||
// 	}
 | 
					}
 | 
				
			||||||
// 	result, err = funcDef.expr.eval(ctx, false)
 | 
					 | 
				
			||||||
// 	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()
 | 
				
			||||||
@ -108,11 +104,10 @@ func evalFuncDef(ctx ExprContext, self *term) (v any, err error) {
 | 
				
			|||||||
		for _, param := range self.children {
 | 
							for _, param := range self.children {
 | 
				
			||||||
			paramList = append(paramList, param.source())
 | 
								paramList = append(paramList, param.source())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		v = newExprFunctor(expr, paramList)
 | 
							v = &funcDefFunctor{
 | 
				
			||||||
		// v = &funcDefFunctor{
 | 
								params: paramList,
 | 
				
			||||||
		// 	params: paramList,
 | 
								expr:   expr,
 | 
				
			||||||
		// 	expr:   expr,
 | 
							}
 | 
				
			||||||
		// }
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		err = errors.New("invalid function definition: the body specification must be an expression")
 | 
							err = errors.New("invalid function definition: the body specification must be an expression")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -74,8 +74,7 @@ func getDataSourceDict(ctx ExprContext, self *term, firstChildValue any) (ds map
 | 
				
			|||||||
		ds = make(map[string]Functor)
 | 
							ds = make(map[string]Functor)
 | 
				
			||||||
		for keyAny, item := range *dictAny {
 | 
							for keyAny, item := range *dictAny {
 | 
				
			||||||
			if key, ok := keyAny.(string); ok {
 | 
								if key, ok := keyAny.(string); ok {
 | 
				
			||||||
				//if functor, ok := item.(*funcDefFunctor); ok {
 | 
									if functor, ok := item.(*funcDefFunctor); ok {
 | 
				
			||||||
				if functor, ok := item.(Functor); ok {
 | 
					 | 
				
			||||||
					ds[key] = functor
 | 
										ds[key] = functor
 | 
				
			||||||
					if index := slices.Index(requiredFields, key); index >= 0 {
 | 
										if index := slices.Index(requiredFields, key); index >= 0 {
 | 
				
			||||||
						foundFields |= 1 << index
 | 
											foundFields |= 1 << index
 | 
				
			||||||
 | 
				
			|||||||
@ -31,21 +31,18 @@ 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 {
 | 
				
			||||||
 | 
								var minArgs, maxArgs int = 0, -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			funcName := rightChild.source()
 | 
								funcName := rightChild.source()
 | 
				
			||||||
			if info, exists, _ := GetFuncInfo(ctx, funcName); exists {
 | 
								if info, exists := ctx.GetFuncInfo(funcName); exists {
 | 
				
			||||||
				// ctx.RegisterFuncInfo(info)
 | 
									minArgs = info.MinArgs()
 | 
				
			||||||
				ctx.RegisterFunc(leftTerm.source(), info.Functor(), info.ReturnType(), info.Params())
 | 
									maxArgs = info.MaxArgs()
 | 
				
			||||||
			} else if funcDef, ok := functor.(*exprFunctor); ok {
 | 
								} else if funcDef, ok := functor.(*funcDefFunctor); ok {
 | 
				
			||||||
				paramSpecs := ForAll(funcDef.params, newFuncParam)
 | 
									l := len(funcDef.params)
 | 
				
			||||||
				// paramCount := len(funcDef.params)
 | 
									minArgs = l
 | 
				
			||||||
				// paramSpecs := make([]ExprFuncParam, paramCount)
 | 
									maxArgs = l
 | 
				
			||||||
				// for i := range paramSpecs {
 | 
					 | 
				
			||||||
				// 	paramSpecs[i] = newFuncParam(funcDef.params[i])
 | 
					 | 
				
			||||||
				// }
 | 
					 | 
				
			||||||
				ctx.RegisterFunc(leftTerm.source(), functor, typeAny, paramSpecs)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				err = self.Errorf("unknown function %s()", funcName)
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								ctx.RegisterFunc(leftTerm.source(), functor, minArgs, maxArgs)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			ctx.UnsafeSetVar(leftTerm.source(), v)
 | 
								ctx.UnsafeSetVar(leftTerm.source(), v)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -66,10 +66,7 @@ func evalAssignCoalesce(ctx ExprContext, self *term) (v any, err error) {
 | 
				
			|||||||
		v = leftValue
 | 
							v = leftValue
 | 
				
			||||||
	} else if rightValue, err = self.children[1].compute(ctx); err == nil {
 | 
						} else if rightValue, err = self.children[1].compute(ctx); err == nil {
 | 
				
			||||||
		if functor, ok := rightValue.(Functor); ok {
 | 
							if functor, ok := rightValue.(Functor); ok {
 | 
				
			||||||
			//ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
 | 
								ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
 | 
				
			||||||
			ctx.RegisterFunc(leftTerm.source(), functor, typeAny, []ExprFuncParam{
 | 
					 | 
				
			||||||
				newFuncParamFlag(paramValue, pfOptional|pfRepeat),
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			v = rightValue
 | 
								v = rightValue
 | 
				
			||||||
			ctx.UnsafeSetVar(leftTerm.source(), rightValue)
 | 
								ctx.UnsafeSetVar(leftTerm.source(), rightValue)
 | 
				
			||||||
 | 
				
			|||||||
@ -20,18 +20,18 @@ func evalContextValue(ctx ExprContext, self *term) (v any, err error) {
 | 
				
			|||||||
	var childValue any
 | 
						var childValue any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var sourceCtx ExprContext
 | 
						var sourceCtx ExprContext
 | 
				
			||||||
	if self.children == nil || len(self.children) == 0 {
 | 
						if len(self.children) == 0 {
 | 
				
			||||||
		sourceCtx = ctx
 | 
							sourceCtx = ctx
 | 
				
			||||||
	} else if self.children[0].symbol() == SymVariable && self.children[0].source() == "global" {
 | 
					 | 
				
			||||||
		sourceCtx = globalCtx
 | 
					 | 
				
			||||||
	} else if childValue, err = self.evalPrefix(ctx); err == nil {
 | 
						} else if childValue, err = self.evalPrefix(ctx); err == nil {
 | 
				
			||||||
		if dc, ok := childValue.(*dataCursor); ok {
 | 
							if dc, ok := childValue.(*dataCursor); ok {
 | 
				
			||||||
			sourceCtx = dc.ctx
 | 
								sourceCtx = dc.ctx
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if sourceCtx != nil {
 | 
						if sourceCtx != nil {
 | 
				
			||||||
		if formatter, ok := sourceCtx.(Formatter); ok {
 | 
							if formatter, ok := ctx.(Formatter); ok {
 | 
				
			||||||
			v = formatter.ToString(0)
 | 
								v = formatter.ToString(0)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
 | 
								keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
 | 
				
			||||||
 | 
				
			|||||||
@ -163,32 +163,46 @@ func TestGeneralParser(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// t.Setenv("EXPR_PATH", ".")
 | 
						// t.Setenv("EXPR_PATH", ".")
 | 
				
			||||||
	// parserTestSpec(t, "General", inputs, 102)
 | 
					 | 
				
			||||||
	parserTest(t, "General", inputs)
 | 
						parserTest(t, "General", inputs)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func parserTestSpec(t *testing.T, section string, inputs []inputType, spec ...int) {
 | 
					 | 
				
			||||||
	succeeded := 0
 | 
					 | 
				
			||||||
	failed := 0
 | 
					 | 
				
			||||||
	for _, count := range spec {
 | 
					 | 
				
			||||||
		good := doTest(t, section, &inputs[count-1], count)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if good {
 | 
					 | 
				
			||||||
			succeeded++
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			failed++
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(spec), succeeded, failed)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func parserTest(t *testing.T, section string, inputs []inputType) {
 | 
					func parserTest(t *testing.T, section string, inputs []inputType) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	succeeded := 0
 | 
						succeeded := 0
 | 
				
			||||||
	failed := 0
 | 
						failed := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i, input := range inputs {
 | 
						for i, input := range inputs {
 | 
				
			||||||
		good := doTest(t, section, &input, i+1)
 | 
							var expr Expr
 | 
				
			||||||
 | 
							var gotResult any
 | 
				
			||||||
 | 
							var gotErr error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ctx := NewSimpleFuncStore()
 | 
				
			||||||
 | 
							parser := NewParser(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							logTest(t, i+1, section, input.source, input.wantResult, input.wantErr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							r := strings.NewReader(input.source)
 | 
				
			||||||
 | 
							scanner := NewScanner(r, DefaultTranslations())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							good := true
 | 
				
			||||||
 | 
							if expr, gotErr = parser.Parse(scanner); gotErr == nil {
 | 
				
			||||||
 | 
								gotResult, gotErr = expr.Eval(ctx)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							eq := reflect.DeepEqual(gotResult, input.wantResult)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !eq /*gotResult != input.wantResult*/ {
 | 
				
			||||||
 | 
								t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult)
 | 
				
			||||||
 | 
								good = false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if gotErr != input.wantErr {
 | 
				
			||||||
 | 
								if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) {
 | 
				
			||||||
 | 
									t.Errorf("%d: %q -> err = <%v>, want <%v>", i+1, input.source, gotErr, input.wantErr)
 | 
				
			||||||
 | 
									good = false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if good {
 | 
							if good {
 | 
				
			||||||
			succeeded++
 | 
								succeeded++
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@ -198,40 +212,6 @@ func parserTest(t *testing.T, section string, inputs []inputType) {
 | 
				
			|||||||
	t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(inputs), succeeded, failed)
 | 
						t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(inputs), succeeded, failed)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func doTest(t *testing.T, section string, input *inputType, count int) (good bool) {
 | 
					 | 
				
			||||||
	var expr Expr
 | 
					 | 
				
			||||||
	var gotResult any
 | 
					 | 
				
			||||||
	var gotErr error
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx := NewSimpleStore()
 | 
					 | 
				
			||||||
	parser := NewParser(ctx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	logTest(t, count, section, input.source, input.wantResult, input.wantErr)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	r := strings.NewReader(input.source)
 | 
					 | 
				
			||||||
	scanner := NewScanner(r, DefaultTranslations())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	good = true
 | 
					 | 
				
			||||||
	if expr, gotErr = parser.Parse(scanner); gotErr == nil {
 | 
					 | 
				
			||||||
		gotResult, gotErr = expr.Eval(ctx)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	eq := reflect.DeepEqual(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)
 | 
					 | 
				
			||||||
		good = false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if gotErr != input.wantErr {
 | 
					 | 
				
			||||||
		if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) {
 | 
					 | 
				
			||||||
			t.Errorf("%d: %q -> got-err = <%v>, expected-err = <%v>", count, input.source, gotErr, input.wantErr)
 | 
					 | 
				
			||||||
			good = false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func logTest(t *testing.T, n int, section, source string, wantResult any, wantErr error) {
 | 
					func logTest(t *testing.T, n int, section, source string, wantResult any, wantErr error) {
 | 
				
			||||||
	if wantErr == nil {
 | 
						if wantErr == nil {
 | 
				
			||||||
		t.Logf("[+]%s nr %3d -- %q  --> %v", section, n, source, wantResult)
 | 
							t.Logf("[+]%s nr %3d -- %q  --> %v", section, n, source, wantResult)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										142
									
								
								simple-func-store.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								simple-func-store.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,142 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// simple-func-store.go
 | 
				
			||||||
 | 
					package expr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SimpleFuncStore struct {
 | 
				
			||||||
 | 
						SimpleVarStore
 | 
				
			||||||
 | 
						funcStore map[string]*funcInfo
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type funcInfo struct {
 | 
				
			||||||
 | 
						name    string
 | 
				
			||||||
 | 
						minArgs int
 | 
				
			||||||
 | 
						maxArgs int
 | 
				
			||||||
 | 
						functor Functor
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (info *funcInfo) ToString(opt FmtOpt) string {
 | 
				
			||||||
 | 
						var sb strings.Builder
 | 
				
			||||||
 | 
						var i int
 | 
				
			||||||
 | 
						sb.WriteString("func(")
 | 
				
			||||||
 | 
						for i = 0; i < info.minArgs; i++ {
 | 
				
			||||||
 | 
							if i > 0 {
 | 
				
			||||||
 | 
								sb.WriteString(", ")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sb.WriteString(fmt.Sprintf("arg%d", i+1))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for ; i < info.maxArgs; i++ {
 | 
				
			||||||
 | 
							sb.WriteString(fmt.Sprintf("arg%d", i+1))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if info.maxArgs < 0 {
 | 
				
			||||||
 | 
							if info.minArgs > 0 {
 | 
				
			||||||
 | 
								sb.WriteString(", ")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sb.WriteString("...")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sb.WriteString(") {...}")
 | 
				
			||||||
 | 
						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
 | 
				
			||||||
 | 
						for _, name := range ctx.EnumFuncs(func(name string) bool { return true }) {
 | 
				
			||||||
 | 
							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) 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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										173
									
								
								simple-store.go
									
									
									
									
									
								
							
							
						
						
									
										173
									
								
								simple-store.go
									
									
									
									
									
								
							@ -1,173 +0,0 @@
 | 
				
			|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 | 
					 | 
				
			||||||
// All rights reserved.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// simple-store.go
 | 
					 | 
				
			||||||
package expr
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"slices"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type SimpleStore struct {
 | 
					 | 
				
			||||||
	varStore  map[string]any
 | 
					 | 
				
			||||||
	funcStore map[string]*funcInfo
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewSimpleStore() *SimpleStore {
 | 
					 | 
				
			||||||
	ctx := &SimpleStore{
 | 
					 | 
				
			||||||
		varStore:  make(map[string]any),
 | 
					 | 
				
			||||||
		funcStore: make(map[string]*funcInfo),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	//ImportBuiltinsFuncs(ctx)
 | 
					 | 
				
			||||||
	return ctx
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleStore) Clone() ExprContext {
 | 
					 | 
				
			||||||
	return &SimpleStore{
 | 
					 | 
				
			||||||
		varStore:  CloneFilteredMap(ctx.varStore, func(name string) bool { return name[0] != '@' }),
 | 
					 | 
				
			||||||
		funcStore: CloneFilteredMap(ctx.funcStore, func(name string) bool { return name[0] != '@' }),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 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 *SimpleStore) ToString(opt FmtOpt) string {
 | 
					 | 
				
			||||||
	var sb strings.Builder
 | 
					 | 
				
			||||||
	varsCtxToBuilder(&sb, ctx, 0)
 | 
					 | 
				
			||||||
	funcsCtxToBuilder(&sb, ctx, 0)
 | 
					 | 
				
			||||||
	return sb.String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleStore) GetVar(varName string) (v any, exists bool) {
 | 
					 | 
				
			||||||
	v, exists = ctx.varStore[varName]
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleStore) UnsafeSetVar(varName string, value any) {
 | 
					 | 
				
			||||||
	// fmt.Printf("[%p] setVar(%v, %v)\n", ctx, varName, value)
 | 
					 | 
				
			||||||
	ctx.varStore[varName] = value
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleStore) 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 *SimpleStore) 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 *SimpleStore) GetFuncInfo(name string) (info ExprFunc, exists bool) {
 | 
					 | 
				
			||||||
	info, exists = ctx.funcStore[name]
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleStore) RegisterFuncInfo(info ExprFunc) {
 | 
					 | 
				
			||||||
	ctx.funcStore[info.Name()], _ = info.(*funcInfo)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleStore) RegisterFunc(name string, functor Functor, returnType string, params []ExprFuncParam) (err error) {
 | 
					 | 
				
			||||||
	var info *funcInfo
 | 
					 | 
				
			||||||
	if info, err = newFuncInfo(name, functor, returnType, params); err == nil {
 | 
					 | 
				
			||||||
		ctx.funcStore[name] = info
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ctx *SimpleStore) 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 *SimpleStore) 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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -72,12 +72,7 @@ func (ctx *SimpleVarStore) Call(name string, args []any) (result any, err error)
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// func (ctx *SimpleVarStore) RegisterFunc(name string, functor Functor, minArgs, maxArgs int) {
 | 
					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) {
 | 
					func (ctx *SimpleVarStore) EnumFuncs(acceptor func(name string) (accept bool)) (funcNames []string) {
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user