Compare commits

...

47 Commits

Author SHA1 Message Date
camoroso 4d910dd069 moved a subset of source file to the kern package 2026-04-27 19:43:37 +02:00
camoroso f100adead3 increased test coverage and splitted some utility functions by OS 2026-04-26 06:16:43 +02:00
camoroso 7d2cf1e687 new operator 'join' 2026-04-25 07:00:30 +02:00
camoroso 49728307f3 t_operator_test.go: added a test for the digest operator 2026-04-25 06:33:35 +02:00
camoroso 20dc502438 new operator 'digest' 2026-04-25 06:25:39 +02:00
camoroso ce7bfc5e3f operator-map/filter.go: added deletion of temporary variables '_index' and '_count' 2026-04-25 06:24:28 +02:00
camoroso 6e98bdd16b new operator 'filter' 2026-04-24 22:42:46 +02:00
camoroso 6ee365bacc new operator 'map' ans general variable access by ${} 2026-04-24 20:11:25 +02:00
camoroso 20d8236325 Iterators: Removed NewAnyIterator(), added NewIterator() 2026-04-24 06:26:00 +02:00
camoroso c39ee7cec0 dict-iterator.go: fixed behaviour of NewDictIterator() with no args 2026-04-23 22:06:23 +02:00
camoroso 9e4252173b Iterator interface now embeds fmt.Stringer 2026-04-23 22:04:41 +02:00
camoroso 2b80ba6789 t_plugin_test.go: TestLoadPluginName() removed due to linkage mismatch 2026-04-23 22:02:41 +02:00
camoroso d7247f97c5 doc: added description of set() and unset() functions defined in the base buiiltin 2026-04-23 19:09:09 +02:00
camoroso 02df7f1c1f Plugin file name extension adapted to the host OS convention (.so on linux, .dll on windows, .dylib on Darwin/MacOS) 2026-04-23 19:06:11 +02:00
camoroso b6b09b2fb1 builtin-os-file: add function fileReadIterator() that creates an iterator over lines of a text file 2026-04-23 19:01:07 +02:00
camoroso 0677180456 builtin-iterator.go/run(): removed default operator (print item) 2026-04-23 18:55:03 +02:00
camoroso b6952444ab builtin-base: added functions set() and unset() 2026-04-21 17:14:51 +02:00
camoroso 6c3a071a02 doc: last change date-time updated 2026-04-21 06:49:58 +02:00
camoroso d7d03b4af8 README: added link to the main Expr documentation hosted on cdn.paas.portale-stac.it 2026-04-21 06:47:15 +02:00
camoroso 49c5cb6a22 doc: progress about builtin functions 2026-04-21 06:45:41 +02:00
camoroso 53d805a832 doc: test commit 2026-04-19 21:27:43 +02:00
camoroso b99ad5def1 Merge branch 'iterator/dict' 2026-04-19 15:18:07 +02:00
camoroso 0d44b8697b doc: more details about iterators over dicts 2026-04-19 15:17:21 +02:00
camoroso 1a7e537921 more tests on iterator over dicts 2026-04-19 15:16:25 +02:00
camoroso 807df0f3a8 Iterator: added support for iterators over dictionaries 2026-04-19 15:08:14 +02:00
camoroso d7dd628fc9 doc: further details about iterator definition 2026-04-19 08:20:40 +02:00
camoroso 1f57ba28dd Doc: progress about builtin modules 2026-04-18 12:21:42 +02:00
camoroso 92bd366380 builtin-base: bool() supports lists and dicts, int() supports fractions 2026-04-18 12:20:05 +02:00
camoroso 7b93c5b4ac doc: begin of iterators description 2026-04-16 10:13:41 +02:00
camoroso 3ba8194ddb Expr.doc, a lot of fixes 2026-04-15 18:17:27 +02:00
camoroso 037565c41e New var() function added to the builtin set 2026-04-15 16:04:12 +02:00
camoroso f8d12b1a93 added TestGoFunction() to test Go functions 2026-04-15 16:03:41 +02:00
camoroso 518d4d8d65 simple-store.go: added function Init() 2026-01-03 09:11:43 +01:00
camoroso d64602cb00 builtin-string.go: fix return type of strLower() and strUpper() 2025-11-15 06:18:38 +01:00
camoroso 4709248828 string builtin: strUpper() and strLower() added 2025-11-13 20:53:07 +01:00
camoroso 5ecf81412e Doc: pre & post incremente/decrement 2025-01-05 12:53:50 +01:00
camoroso ff4db34f7b t_operator_test.go: test on -- and ++ prefix operators 2025-01-05 12:49:36 +01:00
camoroso 0f848071c2 New prefix operators ++ and -- 2025-01-04 18:12:38 +01:00
camoroso 6b3351b324 new prefix operator "!" as logic NOT 2025-01-04 17:47:59 +01:00
camoroso 760c1ee6da New bitwise XOR operator specified by symbol ^ (caret). Iterator dereference is now done by prefixed * (star) 2025-01-03 07:33:17 +01:00
camoroso 5ab6876ea1 term.go: new priority priDereference 2025-01-03 07:28:30 +01:00
camoroso 6268abda8c token.go: new member function Token.SetSymbol() 2025-01-03 07:27:49 +01:00
camoroso d25bd325b7 symbol-map.go: improved detection of incomplete operations 2025-01-03 06:32:55 +01:00
camoroso 01c04feea5 Doc: bitwise operators in the main operator table and special assignment operators table 2025-01-03 05:43:50 +01:00
camoroso 6fc689c46c Added a test to the context type 2025-01-03 05:40:24 +01:00
camoroso eccb0c4dc9 Added new special operators like &= and <<=.
Also made a litle change to scanner function moveOn(): now it moves on
the last char passed and only if there are more than one chars.
2024-12-29 19:26:02 +01:00
camoroso e43823740f Doc: added string splitter operator '/' 2024-12-28 19:22:26 +01:00
120 changed files with 5815 additions and 1846 deletions
+1 -1
View File
@@ -144,4 +144,4 @@ Variables and functions can be added to a context both programmatically and ad a
== Expressions syntax
See #TODO link to doc/Expr.html#
See https://cdn.paas.portale-stac.it/howto/go-pkg/expr/doc/Expr.html[Expr documentation] for a complete reference of the expression syntax and available functions.
+35 -33
View File
@@ -6,6 +6,8 @@ package expr
import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- ast
@@ -19,33 +21,33 @@ func NewAst() *ast {
return &ast{}
}
func (expr *ast) TypeName() string {
func (ast *ast) TypeName() string {
return "Expression"
}
func (expr *ast) ToForest() {
if expr.root != nil {
if expr.forest == nil {
expr.forest = make([]*term, 0)
func (ast *ast) ToForest() {
if ast.root != nil {
if ast.forest == nil {
ast.forest = make([]*term, 0)
}
expr.forest = append(expr.forest, expr.root)
expr.root = nil
ast.forest = append(ast.forest, ast.root)
ast.root = nil
}
}
func (expr *ast) String() string {
func (ast *ast) String() string {
var sb strings.Builder
if expr.root == nil {
if ast.root == nil {
sb.WriteString("(nil)")
} else {
expr.root.toString(&sb)
ast.root.toString(&sb)
}
return sb.String()
}
func (expr *ast) addTokens(tokens ...*Token) (err error) {
func (ast *ast) addTokens(tokens ...*Token) (err error) {
for _, tk := range tokens {
if _, err = expr.addToken(tk); err != nil {
if _, err = ast.addToken(tk); err != nil {
break
}
}
@@ -57,31 +59,31 @@ func (expr *ast) addTokens(tokens ...*Token) (err error) {
// return
// }
func (expr *ast) addToken(tk *Token) (t *term, err error) {
func (ast *ast) addToken(tk *Token) (t *term, err error) {
if t = newTerm(tk); t != nil {
err = expr.addTerm(t)
err = ast.addTerm(t)
} else {
err = tk.Errorf("unexpected token %q", tk.String())
}
return
}
func (expr *ast) addTerm(node *term) (err error) {
if expr.root == nil {
expr.root = node
func (ast *ast) addTerm(node *term) (err error) {
if ast.root == nil {
ast.root = node
} else {
expr.root, err = expr.insert(expr.root, node)
ast.root, err = ast.insert(ast.root, node)
}
return
}
func (expr *ast) insert(tree, node *term) (root *term, err error) {
func (ast *ast) insert(tree, node *term) (root *term, err error) {
if tree.getPriority() < node.getPriority() {
root = tree
if tree.isComplete() {
var subRoot *term
last := tree.removeLastChild()
if subRoot, err = expr.insert(last, node); err == nil {
if subRoot, err = ast.insert(last, node); err == nil {
subRoot.setParent(tree)
}
} else {
@@ -96,22 +98,22 @@ func (expr *ast) insert(tree, node *term) (root *term, err error) {
return
}
func (expr *ast) Finish() {
if expr.root == nil && expr.forest != nil && len(expr.forest) >= 1 {
expr.root = expr.forest[len(expr.forest)-1]
expr.forest = expr.forest[0 : len(expr.forest)-1]
func (ast *ast) Finish() {
if ast.root == nil && ast.forest != nil && len(ast.forest) >= 1 {
ast.root = ast.forest[len(ast.forest)-1]
ast.forest = ast.forest[0 : len(ast.forest)-1]
}
}
func (expr *ast) Eval(ctx ExprContext) (result any, err error) {
expr.Finish()
func (ast *ast) Eval(ctx kern.ExprContext) (result any, err error) {
ast.Finish()
if expr.root != nil {
if ast.root != nil {
// initDefaultVars(ctx)
if expr.forest != nil {
for _, root := range expr.forest {
if result, err = root.compute(ctx); err == nil {
ctx.UnsafeSetVar(ControlLastResult, result)
if ast.forest != nil {
for _, root := range ast.forest {
if result, err = root.Compute(ctx); err == nil {
ctx.UnsafeSetVar(kern.ControlLastResult, result)
} else {
//err = fmt.Errorf("error in expression nr %d: %v", i+1, err)
break
@@ -119,8 +121,8 @@ func (expr *ast) Eval(ctx ExprContext) (result any, err error) {
}
}
if err == nil {
if result, err = expr.root.compute(ctx); err == nil {
ctx.UnsafeSetVar(ControlLastResult, result)
if result, err = ast.root.Compute(ctx); err == nil {
ctx.UnsafeSetVar(kern.ControlLastResult, result)
}
}
// } else {
+15 -11
View File
@@ -4,20 +4,24 @@
// function.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
// ---- Linking with Expr functions
type exprFunctor struct {
baseFunctor
params []ExprFuncParam
kern.BaseFunctor
params []kern.ExprFuncParam
expr Expr
defCtx ExprContext
defCtx kern.ExprContext
}
func (functor *exprFunctor) GetParams() (params []ExprFuncParam) {
func (functor *exprFunctor) GetParams() (params []kern.ExprFuncParam) {
return functor.params
}
func newExprFunctor(e Expr, params []ExprFuncParam, ctx ExprContext) *exprFunctor {
var defCtx ExprContext
func newExprFunctor(e Expr, params []kern.ExprFuncParam, ctx kern.ExprContext) *exprFunctor {
var defCtx kern.ExprContext
if ctx != nil {
defCtx = ctx
}
@@ -28,17 +32,17 @@ func (functor *exprFunctor) TypeName() string {
return "ExprFunctor"
}
func (functor *exprFunctor) GetDefinitionContext() ExprContext {
func (functor *exprFunctor) GetDefinitionContext() kern.ExprContext {
return functor.defCtx
}
func (functor *exprFunctor) InvokeNamed(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func (functor *exprFunctor) InvokeNamed(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var missing []string
for _, p := range functor.params {
if arg, exists := args[p.Name()]; exists {
if funcArg, ok := arg.(Functor); ok {
if funcArg, ok := arg.(kern.Functor); ok {
paramSpecs := funcArg.GetParams()
ctx.RegisterFunc(p.Name(), funcArg, TypeAny, paramSpecs)
ctx.RegisterFunc(p.Name(), funcArg, kern.TypeAny, paramSpecs)
} else {
ctx.UnsafeSetVar(p.Name(), arg)
}
@@ -51,7 +55,7 @@ func (functor *exprFunctor) InvokeNamed(ctx ExprContext, name string, args map[s
}
}
if missing != nil {
err = ErrMissingParams(name, missing)
err = kern.ErrMissingParams(name, missing)
} else {
result, err = functor.expr.Eval(ctx)
}
+147 -76
View File
@@ -9,77 +9,83 @@ import (
"math"
"strconv"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
const (
ParamDenominator = "denominator"
)
func isNilFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
result = args[ParamValue] == nil
func isNilFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
result = args[kern.ParamValue] == nil
return
}
func isIntFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
result = IsInteger(args[ParamValue])
func isIntFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
result = kern.IsInteger(args[kern.ParamValue])
return
}
func isFloatFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
result = IsFloat(args[ParamValue])
func isFloatFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
result = kern.IsFloat(args[kern.ParamValue])
return
}
func isBoolFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
result = IsBool(args[ParamValue])
func isBoolFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
result = kern.IsBool(args[kern.ParamValue])
return
}
func isStringFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
result = IsString(args[ParamValue])
func isStringFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
result = kern.IsString(args[kern.ParamValue])
return
}
func isFractionFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
result = IsFract(args[ParamValue])
func isFractionFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
result = kern.IsFract(args[kern.ParamValue])
return
}
func isRationalFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
result = IsRational(args[ParamValue])
func isRationalFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
result = kern.IsRational(args[kern.ParamValue])
return
}
func isListFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
result = IsList(args[ParamValue])
func isListFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
result = kern.IsList(args[kern.ParamValue])
return
}
func isDictionaryFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
result = IsDict(args[ParamValue])
func isDictionaryFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
result = kern.IsDict(args[kern.ParamValue])
return
}
func boolFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[ParamValue].(type) {
func boolFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[kern.ParamValue].(type) {
case int64:
result = (v != 0)
case *FractionType:
result = v.num != 0
case *kern.FractionType:
result = v.N() != 0
case float64:
result = v != 0.0
case bool:
result = v
case string:
result = len(v) > 0
case *kern.ListType:
result = len(*v) > 0
case *kern.DictType:
result = len(*v) > 0
default:
err = ErrCantConvert(name, v, "bool")
err = kern.ErrCantConvert(name, v, "bool")
}
return
}
func intFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[ParamValue].(type) {
func intFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[kern.ParamValue].(type) {
case int64:
result = v
case float64:
@@ -95,14 +101,16 @@ func intFunc(ctx ExprContext, name string, args map[string]any) (result any, err
if i, err = strconv.Atoi(v); err == nil {
result = int64(i)
}
case *kern.FractionType:
result = int64(v.N() / v.D())
default:
err = ErrCantConvert(name, v, "int")
err = kern.ErrCantConvert(name, v, "int")
}
return
}
func decFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[ParamValue].(type) {
func decFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[kern.ParamValue].(type) {
case int64:
result = float64(v)
case float64:
@@ -118,16 +126,16 @@ func decFunc(ctx ExprContext, name string, args map[string]any) (result any, err
if f, err = strconv.ParseFloat(v, 64); err == nil {
result = f
}
case *FractionType:
result = v.toFloat()
case *kern.FractionType:
result = v.ToFloat()
default:
err = ErrCantConvert(name, v, "float")
err = kern.ErrCantConvert(name, v, "float")
}
return
}
func stringFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[ParamValue].(type) {
func stringFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[kern.ParamValue].(type) {
case int64:
result = strconv.FormatInt(v, 10)
case float64:
@@ -140,105 +148,168 @@ func stringFunc(ctx ExprContext, name string, args map[string]any) (result any,
}
case string:
result = v
case *FractionType:
case *kern.FractionType:
result = v.ToString(0)
case Formatter:
case kern.Formatter:
result = v.ToString(0)
case fmt.Stringer:
result = v.String()
default:
err = ErrCantConvert(name, v, "string")
err = kern.ErrCantConvert(name, v, "string")
}
return
}
func fractFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[ParamValue].(type) {
func fractFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[kern.ParamValue].(type) {
case int64:
var den int64 = 1
var ok bool
if den, ok = args[ParamDenominator].(int64); !ok {
err = ErrExpectedGot(name, "integer", args[ParamDenominator])
err = kern.ErrExpectedGot(name, "integer", args[ParamDenominator])
} else if den == 0 {
err = ErrFuncDivisionByZero(name)
err = kern.ErrFuncDivisionByZero(name)
}
if err == nil {
result = newFraction(v, den)
result = kern.NewFraction(v, den)
}
case float64:
result, err = float64ToFraction(v)
result, err = kern.Float64ToFraction(v)
case bool:
if v {
result = newFraction(1, 1)
result = kern.NewFraction(1, 1)
} else {
result = newFraction(0, 1)
result = kern.NewFraction(0, 1)
}
case string:
result, err = makeGeneratingFraction(v)
case *FractionType:
result, err = kern.MakeGeneratingFraction(v)
case *kern.FractionType:
result = v
default:
err = ErrCantConvert(name, v, "float")
err = kern.ErrCantConvert(name, v, "float")
}
return
}
// func iteratorFunc(ctx ExprContext, name string, args []any) (result any, err error) {
// func iteratorFunc(ctx expr.ExprContext, name string, args []any) (result any, err error) {
// return
// }
func evalFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
if source, ok := args[ParamSource].(string); ok {
var expr Expr
func evalFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if source, ok := args[kern.ParamSource].(string); ok {
var ast Expr
parser := NewParser()
if ctx == nil {
ctx = NewSimpleStore()
ctx = NewSimpleStoreWithoutGlobalContext()
}
r := strings.NewReader(source)
scanner := NewScanner(r, DefaultTranslations())
if expr, err = parser.Parse(scanner); err == nil {
CtrlEnable(ctx, control_export_all)
result, err = expr.Eval(ctx)
if ast, err = parser.Parse(scanner); err == nil {
CtrlEnable(ctx, kern.ControlExportAll)
result, err = ast.Eval(ctx)
}
} else {
err = ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource])
err = kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
}
return
}
func varFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var varName string
var ok bool
if varName, ok = args[kern.ParamName].(string); !ok {
return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName])
}
if result, ok = args[kern.ParamValue]; ok && result != nil {
ctx.GetParent().UnsafeSetVar(varName, result)
// } else {
// err = expr.ErrWrongParamType(name, expr.ParamSource, expr.TypeString, args[expr.ParamSource])
// }
} else if result, ok = ctx.GetVar(varName); !ok {
err = kern.ErrUnknownVar(name, varName)
}
return
}
func setFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var varName string
var ok bool
if varName, ok = args[kern.ParamName].(string); !ok {
return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName])
}
if result, ok = args[kern.ParamValue]; ok {
ctx.GetParent().UnsafeSetVar(varName, result)
} else {
err = kern.ErrWrongParamType(name, kern.ParamValue, kern.TypeAny, args[kern.ParamValue])
}
return
}
func unsetFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var varName string
var ok bool
if varName, ok = args[kern.ParamName].(string); !ok {
return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName])
} else {
ctx.GetParent().DeleteVar(varName)
result = nil
}
return
}
//// import
func ImportBuiltinsFuncs(ctx ExprContext) {
anyParams := []ExprFuncParam{
NewFuncParam(ParamValue),
func ImportBuiltinsFuncs(ctx kern.ExprContext) {
anyParams := []kern.ExprFuncParam{
NewFuncParam(kern.ParamValue),
}
ctx.RegisterFunc("isNil", NewGolangFunctor(isNilFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("isInt", NewGolangFunctor(isIntFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("isFloat", NewGolangFunctor(isFloatFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("isBool", NewGolangFunctor(isBoolFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("isString", NewGolangFunctor(isStringFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("isFract", NewGolangFunctor(isFractionFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("isRational", NewGolangFunctor(isRationalFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("isList", NewGolangFunctor(isListFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("isDict", NewGolangFunctor(isDictionaryFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("isNil", kern.NewGolangFunctor(isNilFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("isInt", kern.NewGolangFunctor(isIntFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("isFloat", kern.NewGolangFunctor(isFloatFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("isBool", kern.NewGolangFunctor(isBoolFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("isString", kern.NewGolangFunctor(isStringFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("isFract", kern.NewGolangFunctor(isFractionFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("isRational", kern.NewGolangFunctor(isRationalFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("isList", kern.NewGolangFunctor(isListFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("isDict", kern.NewGolangFunctor(isDictionaryFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("bool", NewGolangFunctor(boolFunc), TypeBoolean, anyParams)
ctx.RegisterFunc("int", NewGolangFunctor(intFunc), TypeInt, anyParams)
ctx.RegisterFunc("dec", NewGolangFunctor(decFunc), TypeFloat, anyParams)
ctx.RegisterFunc("string", NewGolangFunctor(stringFunc), TypeString, anyParams)
ctx.RegisterFunc("fract", NewGolangFunctor(fractFunc), TypeFraction, []ExprFuncParam{
NewFuncParam(ParamValue),
ctx.RegisterFunc("bool", kern.NewGolangFunctor(boolFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("int", kern.NewGolangFunctor(intFunc), kern.TypeInt, anyParams)
ctx.RegisterFunc("dec", kern.NewGolangFunctor(decFunc), kern.TypeFloat, anyParams)
ctx.RegisterFunc("string", kern.NewGolangFunctor(stringFunc), kern.TypeString, anyParams)
ctx.RegisterFunc("fract", kern.NewGolangFunctor(fractFunc), kern.TypeFraction, []kern.ExprFuncParam{
NewFuncParam(kern.ParamValue),
NewFuncParamFlagDef(ParamDenominator, PfDefault, int64(1)),
})
ctx.RegisterFunc("eval", NewGolangFunctor(evalFunc), TypeAny, []ExprFuncParam{
NewFuncParam(ParamSource),
ctx.RegisterFunc("eval", kern.NewGolangFunctor(evalFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
})
ctx.RegisterFunc("var", kern.NewGolangFunctor(varFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamName),
NewFuncParamFlagDef(kern.ParamValue, PfDefault, nil),
})
ctx.RegisterFunc("set", kern.NewGolangFunctor(setFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamName),
NewFuncParam(kern.ParamValue),
})
ctx.RegisterFunc("unset", kern.NewGolangFunctor(unsetFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamName),
NewFuncParam(kern.ParamValue),
})
}
+13 -11
View File
@@ -8,11 +8,13 @@ import (
"fmt"
"io"
"os"
"git.portale-stac.it/go-pkg/expr/kern"
)
func getStdout(ctx ExprContext) io.Writer {
func getStdout(ctx kern.ExprContext) io.Writer {
var w io.Writer
if wany, exists := ctx.GetVar(ControlStdout); exists && wany != nil {
if wany, exists := ctx.GetVar(kern.ControlStdout); exists && wany != nil {
w, _ = wany.(io.Writer)
}
if w == nil {
@@ -21,9 +23,9 @@ func getStdout(ctx ExprContext) io.Writer {
return w
}
func printFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func printFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var n int = 0
if v, exists := args[ParamItem]; exists && v != nil {
if v, exists := args[kern.ParamItem]; exists && v != nil {
argv := v.([]any)
n, err = fmt.Fprint(getStdout(ctx), argv...)
}
@@ -31,9 +33,9 @@ func printFunc(ctx ExprContext, name string, args map[string]any) (result any, e
return
}
func printLnFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func printLnFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var n int = 0
if v, exists := args[ParamItem]; exists && v != nil {
if v, exists := args[kern.ParamItem]; exists && v != nil {
argv := v.([]any)
n, err = fmt.Fprintln(getStdout(ctx), argv...)
} else {
@@ -43,12 +45,12 @@ func printLnFunc(ctx ExprContext, name string, args map[string]any) (result any,
return
}
func ImportFmtFuncs(ctx ExprContext) {
ctx.RegisterFunc("print", NewGolangFunctor(printFunc), TypeInt, []ExprFuncParam{
NewFuncParamFlag(ParamItem, PfRepeat),
func ImportFmtFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("print", kern.NewGolangFunctor(printFunc), kern.TypeInt, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamItem, PfRepeat),
})
ctx.RegisterFunc("println", NewGolangFunctor(printLnFunc), TypeInt, []ExprFuncParam{
NewFuncParamFlag(ParamItem, PfRepeat),
ctx.RegisterFunc("println", kern.NewGolangFunctor(printLnFunc), kern.TypeInt, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamItem, PfRepeat),
})
}
+14 -12
View File
@@ -7,27 +7,29 @@ package expr
import (
"io"
"os"
"git.portale-stac.it/go-pkg/expr/kern"
)
func importFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func importFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
return importGeneral(ctx, name, args)
}
func importAllFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
CtrlEnable(ctx, control_export_all)
func importAllFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
CtrlEnable(ctx, kern.ControlExportAll)
return importGeneral(ctx, name, args)
}
func importGeneral(ctx ExprContext, name string, args map[string]any) (result any, err error) {
dirList := buildSearchDirList("sources", ENV_EXPR_SOURCE_PATH)
if v, exists := args[ParamFilepath]; exists && v != nil {
func importGeneral(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
dirList := buildSearchDirList(ctx, "sources", ENV_EXPR_SOURCE_PATH)
if v, exists := args[kern.ParamFilepath]; exists && v != nil {
argv := v.([]any)
result, err = doImport(ctx, name, dirList, NewArrayIterator(argv))
}
return
}
func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (result any, err error) {
func doImport(ctx kern.ExprContext, name string, dirList []string, it kern.Iterator) (result any, err error) {
var v any
var sourceFilepath string
@@ -64,12 +66,12 @@ func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (resu
return
}
func ImportImportFuncs(ctx ExprContext) {
ctx.RegisterFunc("import", NewGolangFunctor(importFunc), TypeAny, []ExprFuncParam{
NewFuncParamFlag(ParamFilepath, PfRepeat),
func ImportImportFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("import", kern.NewGolangFunctor(importFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamFilepath, PfRepeat),
})
ctx.RegisterFunc("importAll", NewGolangFunctor(importAllFunc), TypeAny, []ExprFuncParam{
NewFuncParamFlag(ParamFilepath, PfRepeat),
ctx.RegisterFunc("importAll", kern.NewGolangFunctor(importAllFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamFilepath, PfRepeat),
})
}
+26 -25
View File
@@ -7,6 +7,8 @@ package expr
import (
"fmt"
"io"
"git.portale-stac.it/go-pkg/expr/kern"
)
const (
@@ -15,22 +17,24 @@ const (
iterVarStatus = "status"
)
func parseRunArgs(localCtx ExprContext, args map[string]any) (it Iterator, op Functor, err error) {
func parseRunArgs(localCtx kern.ExprContext, args map[string]any) (it kern.Iterator, op kern.Functor, err error) {
var ok bool
if it, ok = args[ParamIterator].(Iterator); !ok {
err = fmt.Errorf("paramter %q must be an iterator, passed %v [%s]", ParamIterator, args[ParamIterator], TypeName(args[ParamIterator]))
if it, ok = args[kern.ParamIterator].(kern.Iterator); !ok {
err = fmt.Errorf("paramter %q must be an iterator, passed %v [%s]", kern.ParamIterator, args[kern.ParamIterator], kern.TypeName(args[kern.ParamIterator]))
return
}
if op, ok = args[iterParamOperator].(Functor); !ok && args[iterParamOperator] != nil {
err = fmt.Errorf("paramter %q must be a function, passed %v [%s]", iterParamOperator, args[iterParamOperator], TypeName(args[iterParamOperator]))
if args[iterParamOperator] != nil {
if op, ok = args[iterParamOperator].(kern.Functor); !ok || op == nil {
err = fmt.Errorf("paramter %q must be a function, passed %v [%s]", iterParamOperator, args[iterParamOperator], kern.TypeName(args[iterParamOperator]))
return
}
}
var vars *DictType
if vars, ok = args[iterParamVars].(*DictType); !ok && args[iterParamVars] != nil {
err = fmt.Errorf("paramter %q must be a dictionary, passed %v [%s]", iterParamVars, args[iterParamVars], TypeName(args[iterParamVars]))
var vars *kern.DictType
if vars, ok = args[iterParamVars].(*kern.DictType); !ok && args[iterParamVars] != nil {
err = fmt.Errorf("paramter %q must be a dictionary, passed %v [%s]", iterParamVars, args[iterParamVars], kern.TypeName(args[iterParamVars]))
return
}
@@ -46,12 +50,12 @@ func parseRunArgs(localCtx ExprContext, args map[string]any) (it Iterator, op Fu
return
}
func runFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
var it Iterator
func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var it kern.Iterator
var ok bool
var op Functor
var op kern.Functor
var v any
var usingDefaultOp = false
// var usingDefaultOp = false
var params map[string]any
var item any
@@ -60,40 +64,37 @@ func runFunc(ctx ExprContext, name string, args map[string]any) (result any, err
if it, op, err = parseRunArgs(localCtx, args); err != nil {
return
} else if op == nil {
op = NewGolangFunctor(printLnFunc)
usingDefaultOp = true
}
for item, err = it.Next(); err == nil; item, err = it.Next() {
if usingDefaultOp {
params = map[string]any{ParamItem: []any{item}}
} else {
params = map[string]any{ParamIndex: it.Index(), ParamItem: item}
}
if op != nil {
params = map[string]any{kern.ParamIndex: it.Index(), kern.ParamItem: item}
if v, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil {
break
} else {
var success bool
if success, ok = ToBool(v); !success || !ok {
if success, ok = kern.ToBool(v); !success || !ok {
break
}
}
}
}
if err == io.EOF {
err = nil
}
if err == nil {
if op == nil {
ctx.UnsafeSetVar(iterVarStatus, it.Count())
}
result, _ = localCtx.GetVar(iterVarStatus)
}
return
}
func ImportIterFuncs(ctx ExprContext) {
ctx.RegisterFunc("run", NewGolangFunctor(runFunc), TypeAny, []ExprFuncParam{
NewFuncParam(ParamIterator),
func ImportIterFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("run", kern.NewGolangFunctor(runFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamIterator),
NewFuncParamFlag(iterParamOperator, PfOptional),
NewFuncParamFlag(iterParamVars, PfOptional),
})
+42 -40
View File
@@ -7,35 +7,37 @@ package expr
import (
"fmt"
"io"
"git.portale-stac.it/go-pkg/expr/kern"
)
func checkNumberParamExpected(funcName string, paramValue any, paramPos, level, subPos int) (err error) {
if !(IsNumber(paramValue) || isFraction(paramValue)) /*|| isList(paramValue)*/ {
if !(kern.IsNumber(paramValue) || kern.IsFraction(paramValue)) /*|| isList(paramValue)*/ {
err = fmt.Errorf("%s(): param nr %d (%d in %d) has wrong type %T, number expected",
funcName, paramPos+1, subPos+1, level, paramValue)
}
return
}
func doAdd(ctx ExprContext, name string, it Iterator, count, level int) (result any, err error) {
func doAdd(ctx kern.ExprContext, name string, it kern.Iterator, count, level int) (result any, err error) {
var sumAsFloat, sumAsFract bool
var floatSum float64 = 0.0
var intSum int64 = 0
var fractSum *FractionType
var fractSum *kern.FractionType
var v any
level++
for v, err = it.Next(); err == nil; v, err = it.Next() {
if list, ok := v.(*ListType); ok {
if list, ok := v.(*kern.ListType); ok {
v = NewListIterator(list, nil)
}
if subIter, ok := v.(Iterator); ok {
if subIter, ok := v.(kern.Iterator); ok {
if v, err = doAdd(ctx, name, subIter, count, level); err != nil {
break
}
if extIter, ok := v.(ExtIterator); ok && extIter.HasOperation(CleanName) {
if _, err = extIter.CallOperation(CleanName, nil); err != nil {
if extIter, ok := v.(kern.ExtIterator); ok && extIter.HasOperation(kern.CleanName) {
if _, err = extIter.CallOperation(kern.CleanName, nil); err != nil {
return
}
}
@@ -45,29 +47,29 @@ func doAdd(ctx ExprContext, name string, it Iterator, count, level int) (result
count++
if !sumAsFloat {
if IsFloat(v) {
if kern.IsFloat(v) {
sumAsFloat = true
if sumAsFract {
floatSum = fractSum.toFloat()
floatSum = fractSum.ToFloat()
} else {
floatSum = float64(intSum)
}
} else if !sumAsFract && isFraction(v) {
fractSum = newFraction(intSum, 1)
} else if !sumAsFract && kern.IsFraction(v) {
fractSum = kern.NewFraction(intSum, 1)
sumAsFract = true
}
}
if sumAsFloat {
floatSum += numAsFloat(v)
floatSum += kern.NumAsFloat(v)
} else if sumAsFract {
var item *FractionType
var item *kern.FractionType
var ok bool
if item, ok = v.(*FractionType); !ok {
if item, ok = v.(*kern.FractionType); !ok {
iv, _ := v.(int64)
item = newFraction(iv, 1)
item = kern.NewFraction(iv, 1)
}
fractSum = sumFract(fractSum, item)
fractSum = kern.SumFract(fractSum, item)
} else {
iv, _ := v.(int64)
intSum += iv
@@ -86,30 +88,30 @@ func doAdd(ctx ExprContext, name string, it Iterator, count, level int) (result
return
}
func addFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
argv := args[ParamValue].([]any)
func addFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
argv := args[kern.ParamValue].([]any)
result, err = doAdd(ctx, name, NewArrayIterator(argv), 0, -1)
return
}
func doMul(ctx ExprContext, name string, it Iterator, count, level int) (result any, err error) {
func doMul(ctx kern.ExprContext, name string, it kern.Iterator, count, level int) (result any, err error) {
var mulAsFloat, mulAsFract bool
var floatProd float64 = 1.0
var intProd int64 = 1
var fractProd *FractionType
var fractProd *kern.FractionType
var v any
level++
for v, err = it.Next(); err == nil; v, err = it.Next() {
if list, ok := v.(*ListType); ok {
if list, ok := v.(*kern.ListType); ok {
v = NewListIterator(list, nil)
}
if subIter, ok := v.(Iterator); ok {
if subIter, ok := v.(kern.Iterator); ok {
if v, err = doMul(ctx, name, subIter, count, level); err != nil {
break
}
if extIter, ok := v.(ExtIterator); ok && extIter.HasOperation(CleanName) {
if _, err = extIter.CallOperation(CleanName, nil); err != nil {
if extIter, ok := v.(kern.ExtIterator); ok && extIter.HasOperation(kern.CleanName) {
if _, err = extIter.CallOperation(kern.CleanName, nil); err != nil {
return
}
}
@@ -121,29 +123,29 @@ func doMul(ctx ExprContext, name string, it Iterator, count, level int) (result
count++
if !mulAsFloat {
if IsFloat(v) {
if kern.IsFloat(v) {
mulAsFloat = true
if mulAsFract {
floatProd = fractProd.toFloat()
floatProd = fractProd.ToFloat()
} else {
floatProd = float64(intProd)
}
} else if !mulAsFract && isFraction(v) {
fractProd = newFraction(intProd, 1)
} else if !mulAsFract && kern.IsFraction(v) {
fractProd = kern.NewFraction(intProd, 1)
mulAsFract = true
}
}
if mulAsFloat {
floatProd *= numAsFloat(v)
floatProd *= kern.NumAsFloat(v)
} else if mulAsFract {
var item *FractionType
var item *kern.FractionType
var ok bool
if item, ok = v.(*FractionType); !ok {
if item, ok = v.(*kern.FractionType); !ok {
iv, _ := v.(int64)
item = newFraction(iv, 1)
item = kern.NewFraction(iv, 1)
}
fractProd = mulFract(fractProd, item)
fractProd = kern.MulFract(fractProd, item)
} else {
iv, _ := v.(int64)
intProd *= iv
@@ -162,19 +164,19 @@ func doMul(ctx ExprContext, name string, it Iterator, count, level int) (result
return
}
func mulFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
argv := args[ParamValue].([]any)
func mulFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
argv := args[kern.ParamValue].([]any)
result, err = doMul(ctx, name, NewArrayIterator(argv), 0, -1)
return
}
func ImportMathFuncs(ctx ExprContext) {
ctx.RegisterFunc("add", NewGolangFunctor(addFunc), TypeNumber, []ExprFuncParam{
NewFuncParamFlagDef(ParamValue, PfDefault|PfRepeat, int64(0)),
func ImportMathFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("add", kern.NewGolangFunctor(addFunc), kern.TypeNumber, []kern.ExprFuncParam{
NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, int64(0)),
})
ctx.RegisterFunc("mul", NewGolangFunctor(mulFunc), TypeNumber, []ExprFuncParam{
NewFuncParamFlagDef(ParamValue, PfDefault|PfRepeat, int64(1)),
ctx.RegisterFunc("mul", kern.NewGolangFunctor(mulFunc), kern.TypeNumber, []kern.ExprFuncParam{
NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, int64(1)),
})
}
+151
View File
@@ -0,0 +1,151 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-os-file.go
package expr
import (
"fmt"
"io"
"slices"
"git.portale-stac.it/go-pkg/expr/kern"
)
const paramHandleOrPath = "handle-or-path"
const fileReadTextIteratorType = "fileReadTextIterator"
type fileReadTextIterator struct {
osReader *osReader
index int
count int
line string
autoClose bool
}
func newReadTextIterator(r *osReader, autoClose bool) *fileReadTextIterator {
return &fileReadTextIterator{osReader: r, index: -1, autoClose: autoClose}
}
func (it *fileReadTextIterator) TypeName() string {
return fileReadTextIteratorType
}
func (it *fileReadTextIterator) String() string {
if it.osReader != nil && it.osReader.fh != nil {
return fmt.Sprintf("$(%s@%q)", fileReadTextIteratorType, it.osReader.fh.Name())
}
return fmt.Sprintf("$(%s@<nil>)", fileReadTextIteratorType)
}
func (it *fileReadTextIterator) Count() int {
return it.count
}
func (it *fileReadTextIterator) Next() (item any, err error) { // must return io.EOF after the last item
if it.osReader.fh != nil {
if it.line, err = it.osReader.reader.ReadString('\n'); err == nil {
it.index++
it.count++
item = it.line[0 : len(it.line)-1]
} else if it.autoClose {
it.Clean()
}
}
return
}
func (it *fileReadTextIterator) Current() (item any, err error) {
if len(it.line) > 0 {
item = it.line[0 : len(it.line)-1]
}
return
}
func (it *fileReadTextIterator) Index() int {
return it.index
}
func (it *fileReadTextIterator) Reset() (err error) {
if _, err = it.osReader.fh.Seek(0, io.SeekStart); err == nil {
it.index = -1
it.count = 0
it.line = ""
}
return
}
func (it *fileReadTextIterator) HasOperation(name string) bool {
return slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName}, name)
}
func (it *fileReadTextIterator) Clean() (err error) {
if it.osReader.fh != nil {
if err = it.osReader.fh.Close(); err == nil {
it.osReader = nil
}
}
return nil
}
func (it *fileReadTextIterator) CallOperation(name string, args map[string]any) (v any, err error) {
switch name {
case kern.NextName:
v, err = it.Next()
case kern.ResetName:
err = it.Reset()
case kern.CleanName:
err = it.Clean()
case kern.IndexName:
v = int64(it.Index())
case kern.CurrentName:
v, err = it.Current()
case kern.CountName:
v = it.count
default:
err = kern.ErrNoOperation(name)
}
return
}
func fileReadIteratorFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle *osReader
var invalidFileHandle any
var ok, autoClose bool
result = nil
if handle, ok = args[paramHandleOrPath].(*osReader); !ok {
if fileName, ok := args[paramHandleOrPath].(string); ok && len(fileName) > 0 {
var handleAny any
if handleAny, err = openFileFunc(ctx, name, map[string]any{kern.ParamFilepath: fileName}); err != nil {
return
}
if handleAny != nil {
handle = handleAny.(*osReader)
autoClose = true
}
} else {
invalidFileHandle = args[paramHandleOrPath]
}
}
if handle != nil {
result = newReadTextIterator(handle, autoClose)
}
if err == nil && (handle == nil || invalidFileHandle != nil) {
err = errInvalidFileHandle(name, invalidFileHandle)
}
return
}
// func ImportOsIterFuncs(ctx ExprContext) {
// ctx.RegisterFunc("fileReadIterator", NewGolangFunctor(fileReadIteratorFunc), TypeIterator, []ExprFuncParam{
// NewFuncParam(paramHandleOrPath),
// })
// }
// func init() {
// RegisterBuiltinModule("os.file", ImportOsIterFuncs, "Operating system file iterator functions")
// }
+41 -35
View File
@@ -9,6 +9,8 @@ import (
"fmt"
"io"
"os"
"git.portale-stac.it/go-pkg/expr/kern"
)
const (
@@ -65,8 +67,8 @@ func errInvalidFileHandle(funcName string, v any) error {
}
}
func createFileFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
if filePath, ok := args[ParamFilepath].(string); ok && len(filePath) > 0 {
func createFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 {
var fh *os.File
if fh, err = os.Create(filePath); err == nil {
result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)}
@@ -77,8 +79,8 @@ func createFileFunc(ctx ExprContext, name string, args map[string]any) (result a
return
}
func openFileFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
if filePath, ok := args[ParamFilepath].(string); ok && len(filePath) > 0 {
func openFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 {
var fh *os.File
if fh, err = os.Open(filePath); err == nil {
result = &osReader{fh: fh, reader: bufio.NewReader(fh)}
@@ -89,8 +91,8 @@ func openFileFunc(ctx ExprContext, name string, args map[string]any) (result any
return
}
func appendFileFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
if filePath, ok := args[ParamFilepath].(string); ok && len(filePath) > 0 {
func appendFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 {
var fh *os.File
if fh, err = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0660); err == nil {
result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)}
@@ -101,13 +103,13 @@ func appendFileFunc(ctx ExprContext, name string, args map[string]any) (result a
return
}
func closeFileFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func closeFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle osHandle
var invalidFileHandle any
var ok bool
if handle, ok = args[ParamHandle].(osHandle); !ok {
invalidFileHandle = args[ParamHandle]
if handle, ok = args[kern.ParamHandle].(osHandle); !ok {
invalidFileHandle = args[kern.ParamHandle]
}
if handle != nil {
@@ -128,18 +130,18 @@ func closeFileFunc(ctx ExprContext, name string, args map[string]any) (result an
return
}
func fileWriteTextFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func fileWriteTextFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle osHandle
var invalidFileHandle any
var ok bool
if handle, ok = args[ParamHandle].(osHandle); !ok {
invalidFileHandle = args[ParamHandle]
if handle, ok = args[kern.ParamHandle].(osHandle); !ok {
invalidFileHandle = args[kern.ParamHandle]
}
if handle != nil {
if w, ok := handle.(*osWriter); ok {
if v, exists := args[ParamItem]; exists {
if v, exists := args[kern.ParamItem]; exists {
argv := v.([]any)
result, err = fmt.Fprint(w.writer, argv...)
}
@@ -154,14 +156,14 @@ func fileWriteTextFunc(ctx ExprContext, name string, args map[string]any) (resul
return
}
func fileReadTextFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func fileReadTextFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle osHandle
var invalidFileHandle any
var ok bool
result = nil
if handle, ok = args[ParamHandle].(osHandle); !ok || args[ParamHandle] == nil {
invalidFileHandle = args[ParamHandle]
if handle, ok = args[kern.ParamHandle].(osHandle); !ok || args[kern.ParamHandle] == nil {
invalidFileHandle = args[kern.ParamHandle]
}
if handle != nil {
@@ -194,14 +196,14 @@ func fileReadTextFunc(ctx ExprContext, name string, args map[string]any) (result
return
}
func fileReadTextAllFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func fileReadTextAllFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle osHandle
var invalidFileHandle any
var ok bool
result = nil
if handle, ok = args[ParamHandle].(osHandle); !ok || args[ParamHandle] == nil {
invalidFileHandle = args[ParamHandle]
if handle, ok = args[kern.ParamHandle].(osHandle); !ok || args[kern.ParamHandle] == nil {
invalidFileHandle = args[kern.ParamHandle]
}
if handle != nil {
@@ -220,35 +222,39 @@ func fileReadTextAllFunc(ctx ExprContext, name string, args map[string]any) (res
return
}
func ImportOsFuncs(ctx ExprContext) {
ctx.RegisterFunc("fileOpen", NewGolangFunctor(openFileFunc), TypeFileHandle, []ExprFuncParam{
NewFuncParam(ParamFilepath),
func ImportOsFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("fileOpen", kern.NewGolangFunctor(openFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{
NewFuncParam(kern.ParamFilepath),
})
ctx.RegisterFunc("fileAppend", NewGolangFunctor(appendFileFunc), TypeFileHandle, []ExprFuncParam{
NewFuncParam(ParamFilepath),
ctx.RegisterFunc("fileAppend", kern.NewGolangFunctor(appendFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{
NewFuncParam(kern.ParamFilepath),
})
ctx.RegisterFunc("fileCreate", NewGolangFunctor(createFileFunc), TypeFileHandle, []ExprFuncParam{
NewFuncParam(ParamFilepath),
ctx.RegisterFunc("fileCreate", kern.NewGolangFunctor(createFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{
NewFuncParam(kern.ParamFilepath),
})
ctx.RegisterFunc("fileClose", NewGolangFunctor(closeFileFunc), TypeBoolean, []ExprFuncParam{
NewFuncParam(ParamHandle),
ctx.RegisterFunc("fileClose", kern.NewGolangFunctor(closeFileFunc), kern.TypeBoolean, []kern.ExprFuncParam{
NewFuncParam(kern.ParamHandle),
})
ctx.RegisterFunc("fileWriteText", NewGolangFunctor(fileWriteTextFunc), TypeInt, []ExprFuncParam{
NewFuncParam(ParamHandle),
NewFuncParamFlagDef(ParamItem, PfDefault|PfRepeat, ""),
ctx.RegisterFunc("fileWriteText", kern.NewGolangFunctor(fileWriteTextFunc), kern.TypeInt, []kern.ExprFuncParam{
NewFuncParam(kern.ParamHandle),
NewFuncParamFlagDef(kern.ParamItem, PfDefault|PfRepeat, ""),
})
ctx.RegisterFunc("fileReadText", NewGolangFunctor(fileReadTextFunc), TypeString, []ExprFuncParam{
NewFuncParam(ParamHandle),
ctx.RegisterFunc("fileReadText", kern.NewGolangFunctor(fileReadTextFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamHandle),
NewFuncParamFlagDef(osLimitCh, PfDefault, "\n"),
})
ctx.RegisterFunc("fileReadTextAll", NewGolangFunctor(fileReadTextAllFunc), TypeString, []ExprFuncParam{
NewFuncParam(ParamHandle),
ctx.RegisterFunc("fileReadTextAll", kern.NewGolangFunctor(fileReadTextAllFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamHandle),
})
ctx.RegisterFunc("fileReadIterator", kern.NewGolangFunctor(fileReadIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{
NewFuncParam(paramHandleOrPath),
})
}
+85 -57
View File
@@ -8,6 +8,8 @@ import (
"fmt"
"io"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
const (
@@ -15,7 +17,7 @@ const (
)
// --- Start of function definitions
func doJoinStr(funcName string, sep string, it Iterator) (result any, err error) {
func doJoinStr(funcName string, sep string, it kern.Iterator) (result any, err error) {
var sb strings.Builder
var v any
for v, err = it.Next(); err == nil; v, err = it.Next() {
@@ -25,7 +27,7 @@ func doJoinStr(funcName string, sep string, it Iterator) (result any, err error)
if s, ok := v.(string); ok {
sb.WriteString(s)
} else {
err = ErrExpectedGot(funcName, TypeString, v)
err = kern.ErrExpectedGot(funcName, kern.TypeString, v)
return
}
}
@@ -36,45 +38,45 @@ func doJoinStr(funcName string, sep string, it Iterator) (result any, err error)
return
}
func joinStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
if sep, ok := args[ParamSeparator].(string); ok {
if v, exists := args[ParamItem]; exists {
func joinStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if sep, ok := args[kern.ParamSeparator].(string); ok {
if v, exists := args[kern.ParamItem]; exists {
argv := v.([]any)
if len(argv) == 1 {
if ls, ok := argv[0].(*ListType); ok {
if ls, ok := argv[0].(*kern.ListType); ok {
result, err = doJoinStr(name, sep, NewListIterator(ls, nil))
} else if it, ok := argv[0].(Iterator); ok {
} else if it, ok := argv[0].(kern.Iterator); ok {
result, err = doJoinStr(name, sep, it)
} else if s, ok := argv[0].(string); ok {
result = s
} else {
err = ErrInvalidParameterValue(name, ParamItem, v)
err = kern.ErrInvalidParameterValue(name, kern.ParamItem, v)
}
} else {
result, err = doJoinStr(name, sep, NewArrayIterator(argv))
}
}
} else {
err = ErrWrongParamType(name, ParamSeparator, TypeString, args[ParamSeparator])
err = kern.ErrWrongParamType(name, kern.ParamSeparator, kern.TypeString, args[kern.ParamSeparator])
}
return
}
func subStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func subStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var start = 0
var count = -1
var source string
var ok bool
if source, ok = args[ParamSource].(string); !ok {
return nil, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource])
if source, ok = args[kern.ParamSource].(string); !ok {
return nil, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
}
if start, err = ToGoInt(args[ParamStart], name+"()"); err != nil {
if start, err = kern.ToGoInt(args[kern.ParamStart], name+"()"); err != nil {
return
}
if count, err = ToGoInt(args[ParamCount], name+"()"); err != nil {
if count, err = kern.ToGoInt(args[kern.ParamCount], name+"()"); err != nil {
return
}
@@ -90,29 +92,29 @@ func subStrFunc(ctx ExprContext, name string, args map[string]any) (result any,
return
}
func trimStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func trimStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var source string
var ok bool
if source, ok = args[ParamSource].(string); !ok {
return nil, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource])
if source, ok = args[kern.ParamSource].(string); !ok {
return nil, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
}
result = strings.TrimSpace(source)
return
}
func startsWithStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func startsWithStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var source, prefix string
var ok bool
result = false
if source, ok = args[ParamSource].(string); !ok {
return result, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource])
if source, ok = args[kern.ParamSource].(string); !ok {
return result, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
}
if prefix, ok = args[ParamPrefix].(string); !ok {
return result, ErrWrongParamType(name, ParamPrefix, TypeString, args[ParamPrefix])
if prefix, ok = args[kern.ParamPrefix].(string); !ok {
return result, kern.ErrWrongParamType(name, kern.ParamPrefix, kern.TypeString, args[kern.ParamPrefix])
}
if strings.HasPrefix(source, prefix) {
result = true
@@ -125,7 +127,7 @@ func startsWithStrFunc(ctx ExprContext, name string, args map[string]any) (resul
break
}
} else {
err = fmt.Errorf("target item nr %d is %s, string expected", i+1, TypeName(targetSpec))
err = fmt.Errorf("target item nr %d is %s, string expected", i+1, kern.TypeName(targetSpec))
break
}
}
@@ -133,18 +135,18 @@ func startsWithStrFunc(ctx ExprContext, name string, args map[string]any) (resul
return
}
func endsWithStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func endsWithStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var source, suffix string
var ok bool
result = false
if source, ok = args[ParamSource].(string); !ok {
return result, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource])
if source, ok = args[kern.ParamSource].(string); !ok {
return result, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
}
if suffix, ok = args[ParamSuffix].(string); !ok {
return result, ErrWrongParamType(name, ParamSuffix, TypeString, args[ParamSuffix])
if suffix, ok = args[kern.ParamSuffix].(string); !ok {
return result, kern.ErrWrongParamType(name, kern.ParamSuffix, kern.TypeString, args[kern.ParamSuffix])
}
if strings.HasPrefix(source, suffix) {
result = true
@@ -157,7 +159,7 @@ func endsWithStrFunc(ctx ExprContext, name string, args map[string]any) (result
break
}
} else {
err = fmt.Errorf("target item nr %d is %s, string expected", i+1, TypeName(targetSpec))
err = fmt.Errorf("target item nr %d is %s, string expected", i+1, kern.TypeName(targetSpec))
break
}
}
@@ -165,24 +167,24 @@ func endsWithStrFunc(ctx ExprContext, name string, args map[string]any) (result
return
}
func splitStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func splitStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var source, sep string
var count int = -1
var parts []string
var ok bool
if source, ok = args[ParamSource].(string); !ok {
return result, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource])
if source, ok = args[kern.ParamSource].(string); !ok {
return result, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
}
if sep, ok = args[ParamSeparator].(string); !ok {
return nil, fmt.Errorf("separator param must be string, got %s (%v)", TypeName(args[ParamSeparator]), args[ParamSeparator])
if sep, ok = args[kern.ParamSeparator].(string); !ok {
return nil, fmt.Errorf("separator param must be string, got %s (%v)", kern.TypeName(args[kern.ParamSeparator]), args[kern.ParamSeparator])
}
if count64, ok := args[ParamCount].(int64); ok { // TODO replace type assertion with toInt()
if count64, ok := args[kern.ParamCount].(int64); ok { // TODO replace type assertion with toInt()
count = int(count64)
} else {
return nil, fmt.Errorf("part count must be integer, got %s (%v)", TypeName(args[ParamCount]), args[ParamCount])
return nil, fmt.Errorf("part count must be integer, got %s (%v)", kern.TypeName(args[kern.ParamCount]), args[kern.ParamCount])
}
if count > 0 {
@@ -192,7 +194,7 @@ func splitStrFunc(ctx ExprContext, name string, args map[string]any) (result any
} else {
parts = []string{}
}
list := make(ListType, len(parts))
list := make(kern.ListType, len(parts))
for i, part := range parts {
list[i] = part
}
@@ -200,42 +202,68 @@ func splitStrFunc(ctx ExprContext, name string, args map[string]any) (result any
return
}
func upperStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if source, ok := args[kern.ParamSource].(string); ok {
result = strings.ToUpper(source)
} else {
err = kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
}
return
}
func lowerStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if source, ok := args[kern.ParamSource].(string); ok {
result = strings.ToLower(source)
} else {
err = kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
}
return
}
// --- End of function definitions
// Import above functions in the context
func ImportStringFuncs(ctx ExprContext) {
ctx.RegisterFunc("strJoin", NewGolangFunctor(joinStrFunc), TypeString, []ExprFuncParam{
NewFuncParam(ParamSeparator),
NewFuncParamFlag(ParamItem, PfRepeat),
func ImportStringFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("strJoin", kern.NewGolangFunctor(joinStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSeparator),
NewFuncParamFlag(kern.ParamItem, PfRepeat),
})
ctx.RegisterFunc("strSub", NewGolangFunctor(subStrFunc), TypeString, []ExprFuncParam{
NewFuncParam(ParamSource),
NewFuncParamFlagDef(ParamStart, PfDefault, int64(0)),
NewFuncParamFlagDef(ParamCount, PfDefault, int64(-1)),
ctx.RegisterFunc("strSub", kern.NewGolangFunctor(subStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
NewFuncParamFlagDef(kern.ParamStart, PfDefault, int64(0)),
NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)),
})
ctx.RegisterFunc("strSplit", NewGolangFunctor(splitStrFunc), "list of "+TypeString, []ExprFuncParam{
NewFuncParam(ParamSource),
NewFuncParamFlagDef(ParamSeparator, PfDefault, ""),
NewFuncParamFlagDef(ParamCount, PfDefault, int64(-1)),
ctx.RegisterFunc("strSplit", kern.NewGolangFunctor(splitStrFunc), "list of "+kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
NewFuncParamFlagDef(kern.ParamSeparator, PfDefault, ""),
NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)),
})
ctx.RegisterFunc("strTrim", NewGolangFunctor(trimStrFunc), TypeString, []ExprFuncParam{
NewFuncParam(ParamSource),
ctx.RegisterFunc("strTrim", kern.NewGolangFunctor(trimStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
})
ctx.RegisterFunc("strStartsWith", NewGolangFunctor(startsWithStrFunc), TypeBoolean, []ExprFuncParam{
NewFuncParam(ParamSource),
NewFuncParam(ParamPrefix),
ctx.RegisterFunc("strStartsWith", kern.NewGolangFunctor(startsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
NewFuncParam(kern.ParamPrefix),
NewFuncParamFlag(strParamOther, PfRepeat),
})
ctx.RegisterFunc("strEndsWith", NewGolangFunctor(endsWithStrFunc), TypeBoolean, []ExprFuncParam{
NewFuncParam(ParamSource),
NewFuncParam(ParamSuffix),
ctx.RegisterFunc("strEndsWith", kern.NewGolangFunctor(endsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
NewFuncParam(kern.ParamSuffix),
NewFuncParamFlag(strParamOther, PfRepeat),
})
ctx.RegisterFunc("strUpper", kern.NewGolangFunctor(upperStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
})
ctx.RegisterFunc("strLower", kern.NewGolangFunctor(lowerStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
})
}
// Register the import function in the import-register.
+5 -3
View File
@@ -6,21 +6,23 @@ package expr
import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
)
type builtinModule struct {
importFunc func(ExprContext)
importFunc func(kern.ExprContext)
description string
imported bool
}
func newBuiltinModule(importFunc func(ExprContext), description string) *builtinModule {
func newBuiltinModule(importFunc func(kern.ExprContext), description string) *builtinModule {
return &builtinModule{importFunc, description, false}
}
var builtinModuleRegister map[string]*builtinModule
func RegisterBuiltinModule(name string, importFunc func(ExprContext), description string) {
func RegisterBuiltinModule(name string, importFunc func(kern.ExprContext), description string) {
if builtinModuleRegister == nil {
builtinModuleRegister = make(map[string]*builtinModule)
}
+43 -41
View File
@@ -7,11 +7,13 @@ package expr
import (
"io"
"slices"
"git.portale-stac.it/go-pkg/expr/kern"
)
type dataCursor struct {
ds map[string]Functor
ctx ExprContext
ds map[string]kern.Functor
ctx kern.ExprContext
initState bool // true if no item has produced yet (this replace di initial Next() call in the contructor)
// cursorValid bool // true if resource is nil or if clean has not yet been called
index int
@@ -19,12 +21,12 @@ type dataCursor struct {
current any
lastErr error
resource any
nextFunc Functor
cleanFunc Functor
resetFunc Functor
nextFunc kern.Functor
cleanFunc kern.Functor
resetFunc kern.Functor
}
func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *dataCursor) {
func NewDataCursor(ctx kern.ExprContext, ds map[string]kern.Functor, resource any) (dc *dataCursor) {
dc = &dataCursor{
ds: ds,
initState: true,
@@ -35,14 +37,14 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da
lastErr: nil,
resource: resource,
ctx: ctx.Clone(),
nextFunc: ds[NextName],
cleanFunc: ds[CleanName],
resetFunc: ds[ResetName],
nextFunc: ds[kern.NextName],
cleanFunc: ds[kern.CleanName],
resetFunc: ds[kern.ResetName],
}
return
}
func (dc *dataCursor) Context() ExprContext {
func (dc *dataCursor) Context() kern.ExprContext {
return dc.ctx
}
@@ -79,27 +81,27 @@ func (dc *dataCursor) String() string {
}
func (dc *dataCursor) HasOperation(name string) (exists bool) {
exists = slices.Contains([]string{CleanName, ResetName, CurrentName, IndexName}, name)
exists = slices.Contains([]string{kern.CleanName, kern.ResetName, kern.CurrentName, kern.IndexName}, name)
if !exists {
f, ok := dc.ds[name]
exists = ok && isFunctor(f)
exists = ok && kern.IsFunctor(f)
}
return
}
func (dc *dataCursor) CallOperation(name string, args map[string]any) (value any, err error) {
if name == IndexName {
if name == kern.IndexName {
value = int64(dc.Index())
} else if name == CleanName {
} else if name == kern.CleanName {
err = dc.Clean()
} else if name == ResetName {
} else if name == kern.ResetName {
err = dc.Reset()
} else if functor, ok := dc.ds[name]; ok && isFunctor(functor) {
ctx := cloneContext(dc.ctx)
} else if functor, ok := dc.ds[name]; ok && kern.IsFunctor(functor) {
ctx := kern.CloneContext(dc.ctx)
value, err = functor.InvokeNamed(ctx, name, args)
exportObjects(dc.ctx, ctx)
kern.ExportObjects(dc.ctx, ctx)
} else {
err = errNoOperation(name)
err = kern.ErrNoOperation(name)
}
return
}
@@ -127,10 +129,10 @@ func (dc *dataCursor) CallOperation(name string, args map[string]any) (value any
func (dc *dataCursor) Reset() (err error) {
if dc.resetFunc != nil {
ctx := cloneContext(dc.ctx)
actualParams := bindActualParams(dc.resetFunc, []any{dc.resource})
_, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams)
exportObjects(dc.ctx, ctx)
ctx := kern.CloneContext(dc.ctx)
actualParams := kern.BindActualParams(dc.resetFunc, []any{dc.resource})
_, err = dc.resetFunc.InvokeNamed(ctx, kern.ResetName, actualParams)
kern.ExportObjects(dc.ctx, ctx)
}
dc.index = -1
dc.count = 0
@@ -142,10 +144,10 @@ func (dc *dataCursor) Reset() (err error) {
func (dc *dataCursor) Clean() (err error) {
if dc.cleanFunc != nil {
ctx := cloneContext(dc.ctx)
actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource})
_, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams)
exportObjects(dc.ctx, ctx)
ctx := kern.CloneContext(dc.ctx)
actualParams := kern.BindActualParams(dc.cleanFunc, []any{dc.resource})
_, err = dc.cleanFunc.InvokeNamed(ctx, kern.CleanName, actualParams)
kern.ExportObjects(dc.ctx, ctx)
}
dc.lastErr = io.EOF
return
@@ -178,13 +180,13 @@ func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at
return
}
func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err error) {
func (dc *dataCursor) checkFilter(filter kern.Functor, item any) (accepted bool, err error) {
var v any
var ok bool
ctx := cloneContext(dc.ctx)
ctx := kern.CloneContext(dc.ctx)
actualParams := bindActualParams(filter, []any{item, dc.index})
if v, err = filter.InvokeNamed(ctx, FilterName, actualParams); err == nil && v != nil {
actualParams := kern.BindActualParams(filter, []any{item, dc.index})
if v, err = filter.InvokeNamed(ctx, kern.FilterName, actualParams); err == nil && v != nil {
if accepted, ok = v.(bool); !ok {
accepted = true // NOTE: A non-boolean value that is not nil means the item has been accepted
}
@@ -192,10 +194,10 @@ func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err
return
}
func (dc *dataCursor) mapItem(mapper Functor, item any) (mappedItem any, err error) {
ctx := cloneContext(dc.ctx)
actualParams := bindActualParams(mapper, []any{item, dc.index})
mappedItem, err = mapper.InvokeNamed(ctx, MapName, actualParams)
func (dc *dataCursor) mapItem(mapper kern.Functor, item any) (mappedItem any, err error) {
ctx := kern.CloneContext(dc.ctx)
actualParams := kern.BindActualParams(mapper, []any{item, dc.index})
mappedItem, err = mapper.InvokeNamed(ctx, kern.MapName, actualParams)
return
}
@@ -213,15 +215,15 @@ func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF af
return
}
current = dc.current
filter := dc.ds[FilterName]
mapper := dc.ds[MapName]
filter := dc.ds[kern.FilterName]
mapper := dc.ds[kern.MapName]
var item any
for item == nil && dc.lastErr == nil {
ctx := cloneContext(dc.ctx)
ctx := kern.CloneContext(dc.ctx)
dc.index++
actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, dc.index})
if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil {
actualParams := kern.BindActualParams(dc.nextFunc, []any{dc.resource, dc.index})
if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, kern.NextName, actualParams); dc.lastErr == nil {
if item == nil {
dc.lastErr = io.EOF
} else {
@@ -239,7 +241,7 @@ func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF af
}
}
}
exportObjects(dc.ctx, ctx)
kern.ExportObjects(dc.ctx, ctx)
}
dc.current = item
if dc.lastErr != nil {
+223
View File
@@ -0,0 +1,223 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// dict-iterator.go
package expr
import (
"fmt"
"io"
"slices"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
type dictIterMode int
const (
dictIterModeKeys dictIterMode = iota
dictIterModeValues
dictIterModeItems
)
type DictIterator struct {
a *kern.DictType
count int
index int
keys []any
iterMode dictIterMode
}
type sortType int
const (
sortTypeNone sortType = iota
sortTypeAsc
sortTypeDesc
sortTypeDefault = sortTypeAsc
)
func (it *DictIterator) makeKeys(m map[any]any, sort sortType) {
it.keys = make([]any, 0, len(m))
if sort == sortTypeNone {
for keyAny := range m {
it.keys = append(it.keys, keyAny)
}
} else {
scalarMap := make(map[string]any, len(m))
scalerKeys := make([]string, 0, len(m))
for keyAny := range m {
keyStr := fmt.Sprint(keyAny)
scalarMap[keyStr] = keyAny
scalerKeys = append(scalerKeys, keyStr)
}
switch sort {
case sortTypeAsc:
slices.Sort(scalerKeys)
case sortTypeDesc:
slices.Sort(scalerKeys)
slices.Reverse(scalerKeys)
}
for _, keyStr := range scalerKeys {
it.keys = append(it.keys, scalarMap[keyStr])
}
}
}
func NewDictIterator(dict *kern.DictType, args []any) (it *DictIterator, err error) {
var sortType = sortTypeNone
var s string
var argAny any
dictIt := &DictIterator{a: dict, count: 0, index: -1, keys: nil, iterMode: dictIterModeKeys}
if len(args) > 0 {
argAny = args[0]
} else {
argAny = "default"
}
if s, err = kern.ToGoString(argAny, "sort type"); err == nil {
switch strings.ToLower(s) {
case "a", "asc":
sortType = sortTypeAsc
case "d", "desc":
sortType = sortTypeDesc
case "n", "none", "nosort", "no-sort":
sortType = sortTypeNone
case "", "default":
sortType = sortTypeDefault
default:
err = fmt.Errorf("invalid sort type %q", s)
}
if err == nil {
if len(args) > 1 {
argAny = args[1]
} else {
argAny = "default"
}
if s, err = kern.ToGoString(argAny, "iteration mode"); err == nil {
switch strings.ToLower(s) {
case "k", "key", "keys":
dictIt.iterMode = dictIterModeKeys
case "v", "value", "values":
dictIt.iterMode = dictIterModeValues
case "i", "item", "items":
dictIt.iterMode = dictIterModeItems
case "", "default":
dictIt.iterMode = dictIterModeKeys
default:
err = fmt.Errorf("invalid iteration mode %q", s)
}
}
}
}
dictIt.makeKeys(*dict, sortType)
return dictIt, err
}
func NewMapIterator(m map[any]any) (it *DictIterator) {
it = &DictIterator{a: (*kern.DictType)(&m), count: 0, index: -1, keys: nil}
it.makeKeys(m, sortTypeNone)
return
}
func (it *DictIterator) String() string {
var l = 0
if it.a != nil {
l = len(*it.a)
}
return fmt.Sprintf("$({#%d})", l)
}
func (it *DictIterator) TypeName() string {
return "DictIterator"
}
func (it *DictIterator) HasOperation(name string) bool {
// yes := name == NextName || name == ResetName || name == IndexName || name == CountName || name == CurrentName
yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName, kern.KeyName, kern.ValueName}, name)
return yes
}
func (it *DictIterator) CallOperation(name string, args map[string]any) (v any, err error) {
switch name {
case kern.NextName:
v, err = it.Next()
case kern.ResetName:
err = it.Reset()
case kern.CleanName:
err = it.Clean()
case kern.IndexName:
v = int64(it.Index())
case kern.CurrentName:
v, err = it.Current()
case kern.CountName:
v = it.count
case kern.KeyName:
if it.index >= 0 && it.index < len(it.keys) {
v = it.keys[it.index]
} else {
err = io.EOF
}
case kern.ValueName:
if it.index >= 0 && it.index < len(it.keys) {
a := *(it.a)
v = a[it.keys[it.index]]
} else {
err = io.EOF
}
default:
err = kern.ErrNoOperation(name)
}
return
}
func (it *DictIterator) Current() (item any, err error) {
if it.index >= 0 && it.index < len(it.keys) {
switch it.iterMode {
case dictIterModeKeys:
item = it.keys[it.index]
case dictIterModeValues:
a := *(it.a)
item = a[it.keys[it.index]]
case dictIterModeItems:
a := *(it.a)
pair := []any{it.keys[it.index], a[it.keys[it.index]]}
item = kern.NewList(pair)
}
} else {
err = io.EOF
}
return
}
func (it *DictIterator) Next() (item any, err error) {
it.index++
if item, err = it.Current(); err != io.EOF {
it.count++
}
return
}
func (it *DictIterator) Index() int {
return it.index
}
func (it *DictIterator) Count() int {
return it.count
}
func (it *DictIterator) Reset() error {
it.index = -1
it.count = 0
return nil
}
func (it *DictIterator) Clean() error {
return nil
}
+818 -43
View File
File diff suppressed because it is too large Load Diff
+1205 -71
View File
File diff suppressed because it is too large Load Diff
+6 -2
View File
@@ -4,9 +4,13 @@
// expr.go
package expr
import (
kern "git.portale-stac.it/go-pkg/expr/kern"
)
// ----Expression interface
type Expr interface {
Typer
Eval(ctx ExprContext) (result any, err error)
kern.Typer
Eval(ctx kern.ExprContext) (result any, err error)
String() string
}
+102 -101
View File
@@ -6,19 +6,20 @@ package expr
import (
"fmt"
"strconv"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
// ---- Function template
type FuncTemplate func(ctx ExprContext, name string, args map[string]any) (result any, err error)
// type FuncTemplate func(ctx expr.ExprContext, name string, args map[string]any) (result any, err error)
// ---- Common functor definition
type baseFunctor struct {
info ExprFunc
type BaseFunctor struct {
info kern.ExprFunc
}
func (functor *baseFunctor) ToString(opt FmtOpt) (s string) {
func (functor *BaseFunctor) ToString(opt kern.FmtOpt) (s string) {
if functor.info != nil {
s = functor.info.ToString(opt)
} else {
@@ -27,23 +28,23 @@ func (functor *baseFunctor) ToString(opt FmtOpt) (s string) {
return s
}
func (functor *baseFunctor) GetParams() (params []ExprFuncParam) {
func (functor *BaseFunctor) GetParams() (params []kern.ExprFuncParam) {
if functor.info != nil {
return functor.info.Params()
} else {
return []ExprFuncParam{}
return []kern.ExprFuncParam{}
}
}
func (functor *baseFunctor) SetFunc(info ExprFunc) {
func (functor *BaseFunctor) SetFunc(info kern.ExprFunc) {
functor.info = info
}
func (functor *baseFunctor) GetFunc() ExprFunc {
func (functor *BaseFunctor) GetFunc() kern.ExprFunc {
return functor.info
}
func (functor *baseFunctor) GetDefinitionContext() ExprContext {
func (functor *BaseFunctor) GetDefinitionContext() kern.ExprContext {
return nil
}
@@ -62,11 +63,11 @@ type funcParamInfo struct {
defaultValue any
}
func NewFuncParam(name string) ExprFuncParam {
func NewFuncParam(name string) kern.ExprFuncParam {
return &funcParamInfo{name: name}
}
func NewFuncParamFlag(name string, flags paramFlags) ExprFuncParam {
func NewFuncParamFlag(name string, flags paramFlags) kern.ExprFuncParam {
return &funcParamInfo{name: name, flags: flags}
}
@@ -79,7 +80,7 @@ func (param *funcParamInfo) Name() string {
}
func (param *funcParamInfo) Type() string {
return TypeAny
return kern.TypeAny
}
func (param *funcParamInfo) IsDefault() bool {
@@ -100,17 +101,17 @@ func (param *funcParamInfo) DefaultValue() any {
// --- Functions
// funcInfo implements ExprFunc
// funcInfo implements expr.ExprFunc
type funcInfo struct {
name string
minArgs int
maxArgs int
functor Functor
formalParams []ExprFuncParam
functor kern.Functor
formalParams []kern.ExprFuncParam
returnType string
}
func newFuncInfo(name string, functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) {
func newFuncInfo(name string, functor kern.Functor, returnType string, params []kern.ExprFuncParam) (info *funcInfo, err error) {
var minArgs = 0
var maxArgs = 0
for _, p := range params {
@@ -138,7 +139,7 @@ func newFuncInfo(name string, functor Functor, returnType string, params []ExprF
return info, nil
}
func (info *funcInfo) Params() []ExprFuncParam {
func (info *funcInfo) Params() []kern.ExprFuncParam {
return info.formalParams
}
@@ -146,7 +147,7 @@ func (info *funcInfo) ReturnType() string {
return info.returnType
}
func (info *funcInfo) ToString(opt FmtOpt) string {
func (info *funcInfo) ToString(opt kern.FmtOpt) string {
var sb strings.Builder
if len(info.Name()) == 0 {
sb.WriteString("func")
@@ -180,7 +181,7 @@ func (info *funcInfo) ToString(opt FmtOpt) string {
if len(info.returnType) > 0 {
sb.WriteString(info.returnType)
} else {
sb.WriteString(TypeAny)
sb.WriteString(kern.TypeAny)
}
sb.WriteString("{}")
return sb.String()
@@ -198,11 +199,11 @@ func (info *funcInfo) MaxArgs() int {
return info.maxArgs
}
func (info *funcInfo) Functor() Functor {
func (info *funcInfo) Functor() kern.Functor {
return info.functor
}
func (info *funcInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) {
func (info *funcInfo) AllocContext(parentCtx kern.ExprContext) (ctx kern.ExprContext) {
if defCtx := info.functor.GetDefinitionContext(); defCtx != nil {
ctx = defCtx.Clone()
ctx.SetParent(defCtx)
@@ -213,7 +214,7 @@ func (info *funcInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) {
return
}
func (info *funcInfo) ParamSpec(paramName string) ExprFuncParam {
func (info *funcInfo) ParamSpec(paramName string) kern.ExprFuncParam {
for _, spec := range info.formalParams {
if spec.Name() == paramName {
return spec
@@ -222,7 +223,7 @@ func (info *funcInfo) ParamSpec(paramName string) ExprFuncParam {
return nil
}
func initActualParams(ctx ExprContext, info ExprFunc, callTerm *term) (actualParams map[string]any, err error) {
func initActualParams(ctx kern.ExprContext, info kern.ExprFunc, callTerm *term) (actualParams map[string]any, err error) {
var varArgs []any
var varName string
@@ -237,10 +238,10 @@ func initActualParams(ctx ExprContext, info ExprFunc, callTerm *term) (actualPar
for i, tree := range callTerm.children {
var paramValue any
paramCtx := ctx.Clone()
if paramValue, err = tree.compute(paramCtx); err != nil {
if paramValue, err = tree.Compute(paramCtx); err != nil {
break
}
if paramName, namedParam := getAssignVarName(tree); namedParam {
if paramName, namedParam := kern.GetAssignVarName(tree); namedParam {
if info.ParamSpec(paramName) == nil {
err = fmt.Errorf("%s(): unknown param %q", info.Name(), paramName)
break
@@ -260,7 +261,7 @@ func initActualParams(ctx ExprContext, info ExprFunc, callTerm *term) (actualPar
actualParams[spec.Name()] = paramValue
}
} else {
err = ErrTooManyParams(info.Name(), len(formalParams), len(callTerm.children))
err = kern.ErrTooManyParams(info.Name(), len(formalParams), len(callTerm.children))
break
}
} else {
@@ -279,7 +280,7 @@ func initActualParams(ctx ExprContext, info ExprFunc, callTerm *term) (actualPar
func (info *funcInfo) PrepareCall(name string, actualParams map[string]any) (err error) {
passedCount := len(actualParams)
if info.MinArgs() > passedCount {
err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
err = kern.ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
return
}
@@ -301,86 +302,86 @@ func (info *funcInfo) PrepareCall(name string, actualParams map[string]any) (err
}
if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) {
err = ErrTooManyParams(name, info.MaxArgs(), len(actualParams))
err = kern.ErrTooManyParams(name, info.MaxArgs(), len(actualParams))
}
return
}
// ----- Call a function ---
func getAssignVarName(t *term) (name string, ok bool) {
if ok = t.symbol() == SymEqual; ok {
name = t.children[0].source()
}
return
}
// func getAssignVarName(t *term) (name string, ok bool) {
// if ok = t.symbol() == SymEqual; ok {
// name = t.children[0].source()
// }
// return
// }
func CallFunctionByTerm(parentCtx ExprContext, name string, callTerm *term) (result any, err error) {
var actualParams map[string]any
if info, exists := GetFuncInfo(parentCtx, name); exists {
if actualParams, err = initActualParams(parentCtx, info, callTerm); err == nil {
ctx := info.AllocContext(parentCtx)
if err = info.PrepareCall(name, actualParams); err == nil {
functor := info.Functor()
result, err = functor.InvokeNamed(ctx, name, actualParams)
exportObjectsToParent(ctx)
}
}
} else {
err = fmt.Errorf("unknown function %s()", name)
}
return
}
func CallFunctionByArgs(parentCtx ExprContext, name string, args []any) (result any, err error) {
var actualParams map[string]any
if info, exists := GetFuncInfo(parentCtx, name); exists {
functor := info.Functor()
actualParams = bindActualParams(functor, args)
ctx := info.AllocContext(parentCtx)
if err = info.PrepareCall(name, actualParams); err == nil {
result, err = functor.InvokeNamed(ctx, name, actualParams)
exportObjectsToParent(ctx)
}
} else {
err = fmt.Errorf("unknown function %s()", name)
}
return
}
func CallFunctionByParams(parentCtx ExprContext, name string, actualParams map[string]any) (result any, err error) {
// func CallFunctionByTerm(parentCtx expr.ExprContext, name string, callTerm *term) (result any, err error) {
// var actualParams map[string]any
if info, exists := GetFuncInfo(parentCtx, name); exists {
functor := info.Functor()
ctx := info.AllocContext(parentCtx)
if err = info.PrepareCall(name, actualParams); err == nil {
result, err = functor.InvokeNamed(ctx, name, actualParams)
exportObjectsToParent(ctx)
}
} else {
err = fmt.Errorf("unknown function %s()", name)
}
return
}
// if info, exists := GetFuncInfo(parentCtx, name); exists {
// if actualParams, err = initActualParams(parentCtx, info, callTerm); err == nil {
// ctx := info.AllocContext(parentCtx)
// if err = info.PrepareCall(name, actualParams); err == nil {
// functor := info.Functor()
// result, err = functor.InvokeNamed(ctx, name, actualParams)
// exportObjectsToParent(ctx)
// }
// }
// } else {
// err = fmt.Errorf("unknown function %s()", name)
// }
// return
// }
func GetParam(args map[string]any, paramName string, paramNum int) (value any, exists bool) {
if value, exists = args[paramName]; !exists {
if paramNum > 0 && paramNum <= len(args) {
value, exists = args["arg"+strconv.Itoa(paramNum)]
}
}
return
}
// func CallFunctionByArgs(parentCtx expr.ExprContext, name string, args []any) (result any, err error) {
// var actualParams map[string]any
// if info, exists := GetFuncInfo(parentCtx, name); exists {
// functor := info.Functor()
// actualParams = bindActualParams(functor, args)
// ctx := info.AllocContext(parentCtx)
// if err = info.PrepareCall(name, actualParams); err == nil {
// result, err = functor.InvokeNamed(ctx, name, actualParams)
// exportObjectsToParent(ctx)
// }
// } else {
// err = fmt.Errorf("unknown function %s()", name)
// }
// return
// }
func bindActualParams(functor Functor, args []any) (actualParams map[string]any) {
formalParams := functor.GetParams()
actualParams = make(map[string]any, len(args))
for i, arg := range args {
if i < len(formalParams) {
actualParams[formalParams[i].Name()] = arg
} else {
actualParams["arg"+strconv.Itoa(i+1)] = arg
}
}
return
}
// func CallFunctionByParams(parentCtx expr.ExprContext, name string, actualParams map[string]any) (result any, err error) {
// //var actualParams map[string]any
// if info, exists := GetFuncInfo(parentCtx, name); exists {
// functor := info.Functor()
// ctx := info.AllocContext(parentCtx)
// if err = info.PrepareCall(name, actualParams); err == nil {
// result, err = functor.InvokeNamed(ctx, name, actualParams)
// exportObjectsToParent(ctx)
// }
// } else {
// err = fmt.Errorf("unknown function %s()", name)
// }
// return
// }
// func GetParam(args map[string]any, paramName string, paramNum int) (value any, exists bool) {
// if value, exists = args[paramName]; !exists {
// if paramNum > 0 && paramNum <= len(args) {
// value, exists = args["arg"+strconv.Itoa(paramNum)]
// }
// }
// return
// }
// func bindActualParams(functor Functor, args []any) (actualParams map[string]any) {
// formalParams := functor.GetParams()
// actualParams = make(map[string]any, len(args))
// for i, arg := range args {
// if i < len(formalParams) {
// actualParams[formalParams[i].Name()] = arg
// } else {
// actualParams["arg"+strconv.Itoa(i+1)] = arg
// }
// }
// return
// }
+43 -73
View File
@@ -7,20 +7,25 @@ package expr
import (
"path/filepath"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
var globalCtx *SimpleStore
//var globalCtx *SimpleStore
func ImportInContext(name string) (exists bool) {
func ImportInContext(ctx kern.ExprContext, name string) (exists bool) {
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
var mod *builtinModule
if mod, exists = builtinModuleRegister[name]; exists {
mod.importFunc(globalCtx)
mod.imported = true
}
}
return
}
func ImportInContextByGlobPattern(pattern string) (count int, err error) {
func ImportInContextByGlobPattern(ctx kern.ExprContext, pattern string) (count int, err error) {
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
var matched bool
for name, mod := range builtinModuleRegister {
if matched, err = filepath.Match(pattern, name); err == nil {
@@ -33,75 +38,37 @@ func ImportInContextByGlobPattern(pattern string) (count int, err error) {
break
}
}
return
}
func GetVar(ctx ExprContext, name string) (value any, exists bool) {
if value, exists = ctx.GetVar(name); !exists {
value, exists = globalCtx.GetVar(name)
}
return
}
func GetLocalFuncInfo(ctx ExprContext, name string) (item ExprFunc, exists bool) {
var v any
if len(name) > 0 {
if v, exists = ctx.GetVar(name); exists && isFunctor(v) {
f, _ := v.(Functor)
item = f.GetFunc()
} else {
item, exists = ctx.GetFuncInfo(name)
}
}
return
}
func GetFuncInfo(ctx ExprContext, name string) (item ExprFunc, exists bool) {
// if len(name) > 0 {
// if item, exists = GetLocalFuncInfo(ctx, name); exists {
// ownerCtx = ctx
// } else if item, exists = globalCtx.GetFuncInfo(name); exists {
// ownerCtx = globalCtx
// }
// }
item, exists, _ = GetFuncInfoAndOwner(ctx, name)
return
}
func GetFuncInfoAndOwner(ctx ExprContext, name string) (item ExprFunc, exists bool, ownerCtx ExprContext) {
if len(name) > 0 {
if item, exists = GetLocalFuncInfo(ctx, name); exists {
ownerCtx = ctx
} else if item, exists = globalCtx.GetFuncInfo(name); exists {
ownerCtx = globalCtx
}
}
return
}
func GlobalCtrlSet(name string, newValue any) (currentValue any) {
func GlobalCtrlSet(ctx kern.ExprContext, name string, newValue any) (currentValue any) {
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
if !strings.HasPrefix(name, "_") {
name = "_" + name
}
currentValue, _ = globalCtx.GetVar(name)
currentValue, _ = globalCtx.GetVar(name)
globalCtx.SetVar(name, newValue)
}
return currentValue
}
func GlobalCtrlGet(name string) (currentValue any) {
func GlobalCtrlGet(ctx kern.ExprContext, name string) (currentValue any) {
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
if !strings.HasPrefix(name, "_") {
name = "_" + name
}
currentValue, _ = globalCtx.GetVar(name)
}
return currentValue
}
func CtrlEnable(ctx ExprContext, name string) (currentStatus bool) {
func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) {
if !strings.HasPrefix(name, "_") {
name = "_" + name
}
if v, exists := ctx.GetVar(name); exists && IsBool(v) {
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
currentStatus, _ = v.(bool)
}
@@ -109,11 +76,11 @@ func CtrlEnable(ctx ExprContext, name string) (currentStatus bool) {
return currentStatus
}
func CtrlDisable(ctx ExprContext, name string) (currentStatus bool) {
func CtrlDisable(ctx kern.ExprContext, name string) (currentStatus bool) {
if !strings.HasPrefix(name, "_") {
name = "_" + name
}
if v, exists := ctx.GetVar(name); exists && IsBool(v) {
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
currentStatus, _ = v.(bool)
}
@@ -121,36 +88,39 @@ func CtrlDisable(ctx ExprContext, name string) (currentStatus bool) {
return currentStatus
}
func CtrlIsEnabled(ctx ExprContext, name string) (status bool) {
var v any
var exists bool
// func CtrlIsEnabled(ctx ExprContext, name string) (status bool) {
// var v any
// var exists bool
if !strings.HasPrefix(name, "_") {
name = "_" + name
}
// if !strings.HasPrefix(name, "_") {
// name = "_" + name
// }
if v, exists = ctx.GetVar(name); !exists {
v, exists = globalCtx.GetVar(name)
}
// if v, exists = ctx.GetVar(name); !exists {
// v, exists = globalCtx.GetVar(name)
// }
if exists {
if b, ok := v.(bool); ok {
status = b
}
}
return
}
// if exists {
// if b, ok := v.(bool); ok {
// status = b
// }
// }
// return
// }
func getControlString(name string) (s string, exists bool) {
func getControlString(ctx kern.ExprContext, name string) (s string, exists bool) {
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
var v any
if v, exists = globalCtx.GetVar(name); exists {
s, exists = v.(string)
}
}
return
}
func init() {
globalCtx = NewSimpleStore()
initDefaultVars(globalCtx)
ImportBuiltinsFuncs(globalCtx)
func InitGlobal() (ctx kern.ExprContext) {
ctx = NewSimpleStoreWithoutGlobalContext()
kern.InitDefaultVars(ctx)
ImportBuiltinsFuncs(ctx)
return
}
+1 -1
View File
@@ -53,7 +53,7 @@ func (r *Reticle) computeCharWidth() {
if v := ref.node.value(); v != nil {
ref.label = fmt.Sprintf("%v", v)
} else {
ref.label = ref.node.source()
ref.label = ref.node.Source()
}
r.colsWidth[c] = max(r.colsWidth[c], len(ref.label)+2) // +2 to make room for brakets
}
+13 -11
View File
@@ -9,9 +9,11 @@ import (
"io"
"os"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
func EvalString(ctx ExprContext, source string) (result any, err error) {
func EvalString(ctx kern.ExprContext, source string) (result any, err error) {
var tree *ast
r := strings.NewReader(source)
@@ -34,21 +36,21 @@ func EvalStringA(source string, args ...Arg) (result any, err error) {
}
func EvalStringV(source string, args []Arg) (result any, err error) {
ctx := NewSimpleStore()
ctx := NewSimpleStoreWithoutGlobalContext()
for _, arg := range args {
if isFunc(arg.Value) {
if f, ok := arg.Value.(FuncTemplate); ok {
functor := NewGolangFunctor(f)
if kern.IsFunc(arg.Value) {
if f, ok := arg.Value.(kern.FuncTemplate); ok {
functor := kern.NewGolangFunctor(f)
// ctx.RegisterFunc(arg.Name, functor, 0, -1)
ctx.RegisterFunc(arg.Name, functor, TypeAny, []ExprFuncParam{
NewFuncParamFlagDef(ParamValue, PfDefault|PfRepeat, 0),
ctx.RegisterFunc(arg.Name, functor, kern.TypeAny, []kern.ExprFuncParam{
NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, 0),
})
} else {
err = fmt.Errorf("invalid function specification: %q", arg.Name)
}
} else if integer, ok := anyInteger(arg.Value); ok {
} else if integer, ok := kern.AnyInteger(arg.Value); ok {
ctx.SetVar(arg.Name, integer)
} else if float, ok := anyFloat(arg.Value); ok {
} else if float, ok := kern.AnyFloat(arg.Value); ok {
ctx.SetVar(arg.Name, float)
} else if _, ok := arg.Value.(string); ok {
ctx.SetVar(arg.Name, arg.Value)
@@ -65,7 +67,7 @@ func EvalStringV(source string, args []Arg) (result any, err error) {
return
}
func EvalStream(ctx ExprContext, r io.Reader) (result any, err error) {
func EvalStream(ctx kern.ExprContext, r io.Reader) (result any, err error) {
var tree *ast
scanner := NewScanner(r, DefaultTranslations())
parser := NewParser()
@@ -76,7 +78,7 @@ func EvalStream(ctx ExprContext, r io.Reader) (result any, err error) {
return
}
func EvalFile(ctx ExprContext, filePath string) (result any, err error) {
func EvalFile(ctx kern.ExprContext, filePath string) (result any, err error) {
var fh *os.File
if fh, err = os.Open(filePath); err != nil {
return nil, err
+22 -8
View File
@@ -11,6 +11,8 @@ import (
"path"
"path/filepath"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
const (
@@ -19,8 +21,8 @@ const (
)
func checkStringParamExpected(funcName string, paramValue any, paramPos int) (err error) {
if !(IsString(paramValue) /*|| isList(paramValue)*/) {
err = fmt.Errorf("%s(): param nr %d has wrong type %s, string expected", funcName, paramPos+1, TypeName(paramValue))
if !(kern.IsString(paramValue) /*|| isList(paramValue)*/) {
err = fmt.Errorf("%s(): param nr %d has wrong type %s, string expected", funcName, paramPos+1, kern.TypeName(paramValue))
}
return
}
@@ -45,8 +47,8 @@ func addEnvImportDirs(envVarName string, dirList []string) []string {
return dirList
}
func addSearchDirs(endingPath string, dirList []string) []string {
if dirSpec, exists := getControlString(ControlSearchPath); exists {
func addSearchDirs(ctx kern.ExprContext, endingPath string, dirList []string) []string {
if dirSpec, exists := getControlString(ctx, kern.ControlSearchPath); exists {
dirs := strings.Split(dirSpec, ":")
if dirList == nil {
dirList = dirs
@@ -63,9 +65,9 @@ func addSearchDirs(endingPath string, dirList []string) []string {
return dirList
}
func buildSearchDirList(endingPath, envVarName string) (dirList []string) {
func buildSearchDirList(ctx kern.ExprContext, endingPath, envVarName string) (dirList []string) {
dirList = addEnvImportDirs(envVarName, dirList)
dirList = addSearchDirs(endingPath, dirList)
dirList = addSearchDirs(ctx, endingPath, dirList)
return
}
@@ -76,14 +78,26 @@ func isFile(filePath string) bool {
func searchAmongPath(filename string, dirList []string) (filePath string) {
var err error
suffix := SHAREDLIBRARY_EXTENSION
if strings.HasSuffix(filename, ".debug") {
suffix += ".debug"
}
for _, dir := range dirList {
if dir, err = ExpandPath(dir); err != nil {
if dir, err = kern.ExpandPath(dir); err != nil {
continue
}
if fullPath := path.Join(dir, filename); isFile(fullPath) {
filePath = fullPath
break
}
subdir := strings.TrimSuffix(filename, suffix)
if fullPath := path.Join(dir, subdir, filename); isFile(fullPath) {
filePath = fullPath
break
}
}
return
}
@@ -94,7 +108,7 @@ func isPathRelative(filePath string) bool {
}
func makeFilepath(filename string, dirList []string) (filePath string, err error) {
if filename, err = ExpandPath(filename); err != nil {
if filename, err = kern.ExpandPath(filename); err != nil {
return
}
+29
View File
@@ -0,0 +1,29 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// iter-factory.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
func NewIterator(value any) (it kern.Iterator, err error) {
if value == nil {
return NewArrayIterator([]any{}), nil
}
switch v := value.(type) {
case *kern.ListType:
it = NewListIterator(v, nil)
case *kern.DictType:
it, err = NewDictIterator(v, nil)
case []any:
it = NewArrayIterator(v)
case kern.Iterator:
it = v
default:
it = NewArrayIterator([]any{value})
}
return
}
@@ -2,11 +2,11 @@
// All rights reserved.
// bind-go-function.go
package expr
package kern
// ---- Linking with Go functions
type golangFunctor struct {
baseFunctor
BaseFunctor
f FuncTemplate
}
+7 -3
View File
@@ -2,7 +2,7 @@
// All rights reserved.
// common-errors.go
package expr
package kern
import (
"fmt"
@@ -80,8 +80,12 @@ func ErrUnknownParam(funcName, paramName string) error {
return fmt.Errorf("%s(): unknown parameter %q", funcName, paramName)
}
func ErrUnknownVar(funcName, varName string) error {
return fmt.Errorf("%s(): unknown variable %q", funcName, varName)
}
// --- Operator errors
func ErrLeftOperandMustBeVariable(leftTerm, opTerm *term) error {
return leftTerm.Errorf("left operand of %q must be a variable", opTerm.source())
func ErrLeftOperandMustBeVariable(leftTerm, opTerm Term) error {
return leftTerm.Errorf("left operand of %q must be a variable", opTerm.Source())
}
+1 -1
View File
@@ -2,7 +2,7 @@
// All rights reserved.
// common-params.go
package expr
package kern
const (
ParamArgs = "args"
@@ -2,7 +2,7 @@
// All rights reserved.
// common-type-names.go
package expr
package kern
const (
TypeAny = "any"
@@ -13,6 +13,7 @@ const (
TypeFileHandle = "file-handle"
TypeInt = "integer"
TypeItem = "item"
TypeIterator = "iterator"
TypeNumber = "number"
TypePair = "pair"
TypeString = "string"
@@ -2,9 +2,9 @@
// All rights reserved.
// context-helpers.go
package expr
package kern
func cloneContext(sourceCtx ExprContext) (clonedCtx ExprContext) {
func CloneContext(sourceCtx ExprContext) (clonedCtx ExprContext) {
if sourceCtx != nil {
clonedCtx = sourceCtx.Clone()
}
@@ -25,8 +25,8 @@ func exportFunc(ctx ExprContext, name string, info ExprFunc) {
ctx.RegisterFunc(name, info.Functor(), info.ReturnType(), info.Params())
}
func exportObjects(destCtx, sourceCtx ExprContext) {
exportAll := CtrlIsEnabled(sourceCtx, control_export_all)
func ExportObjects(destCtx, sourceCtx ExprContext) {
exportAll := CtrlIsEnabled(sourceCtx, ControlExportAll)
// fmt.Printf("Exporting from sourceCtx [%p] to destCtx [%p] -- exportAll=%t\n", sourceCtx, destCtx, exportAll)
// Export variables
for _, refName := range sourceCtx.EnumVars(func(name string) bool { return (exportAll || name[0] == '@') && !(name[0] == '_') }) {
@@ -44,6 +44,6 @@ func exportObjects(destCtx, sourceCtx ExprContext) {
func exportObjectsToParent(sourceCtx ExprContext) {
if parentCtx := sourceCtx.GetParent(); parentCtx != nil {
exportObjects(parentCtx, sourceCtx)
ExportObjects(parentCtx, sourceCtx)
}
}
+26 -3
View File
@@ -2,7 +2,9 @@
// All rights reserved.
// control.go
package expr
package kern
import "strings"
// Preset control variables
const (
@@ -16,7 +18,7 @@ const (
// Other control variables
const (
control_export_all = "_export_all"
ControlExportAll = "_export_all"
)
// Initial values
@@ -24,13 +26,34 @@ const (
init_search_path = "~/.local/lib/go-pkg/expr:/usr/local/lib/go-pkg/expr:/usr/lib/go-pkg/expr"
)
func CtrlIsEnabled(ctx ExprContext, name string) (status bool) {
var v any
var exists bool
if !strings.HasPrefix(name, "_") {
name = "_" + name
}
if v, exists = ctx.GetVar(name); !exists {
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
v, exists = globalCtx.GetVar(name)
}
}
if exists {
if b, ok := v.(bool); ok {
status = b
}
}
return
}
func SetCtrl(ctx ExprContext, name string, value any) (current any) {
current, _ = ctx.GetVar(name)
ctx.UnsafeSetVar(name, value)
return
}
func initDefaultVars(ctx ExprContext) {
func InitDefaultVars(ctx ExprContext) {
if _, exists := ctx.GetVar(ControlPreset); exists {
return
}
+8 -8
View File
@@ -2,7 +2,7 @@
// All rights reserved.
// dict-type.go
package expr
package kern
import (
"fmt"
@@ -32,8 +32,8 @@ func NewDict(dictAny map[any]any) (dict *DictType) {
return
}
func newDict(dictAny map[any]*term) (dict *DictType) {
// TODO Change wi a call to NewDict()
func newDict(dictAny map[any]Term) (dict *DictType) {
// TODO Change with a call to NewDict()
var d DictType
if dictAny != nil {
d = make(DictType, len(dictAny))
@@ -110,7 +110,7 @@ func (dict *DictType) ToString(opt FmtOpt) string {
sb.WriteString(": ")
if formatter, ok := value.(Formatter); ok {
sb.WriteString(formatter.ToString(opt))
} else if t, ok := value.(*term); ok {
} else if t, ok := value.(Term); ok {
sb.WriteString(t.String())
} else {
sb.WriteString(fmt.Sprintf("%#v", value))
@@ -129,7 +129,7 @@ func (dict *DictType) TypeName() string {
return "dict"
}
func (dict *DictType) hasKey(target any) (ok bool) {
func (dict *DictType) HasKey(target any) (ok bool) {
for key := range *dict {
if ok = reflect.DeepEqual(key, target); ok {
break
@@ -138,7 +138,7 @@ func (dict *DictType) hasKey(target any) (ok bool) {
return
}
func (dict *DictType) clone() (c *DictType) {
func (dict *DictType) Clone() (c *DictType) {
c = newDict(nil)
for k, v := range *dict {
(*c)[k] = v
@@ -146,7 +146,7 @@ func (dict *DictType) clone() (c *DictType) {
return
}
func (dict *DictType) merge(second *DictType) {
func (dict *DictType) Merge(second *DictType) {
if second != nil {
for k, v := range *second {
(*dict)[k] = v
@@ -154,7 +154,7 @@ func (dict *DictType) merge(second *DictType) {
}
}
func (dict *DictType) setItem(key any, value any) (err error) {
func (dict *DictType) SetItem(key any, value any) (err error) {
(*dict)[key] = value
return
}
+3 -1
View File
@@ -2,13 +2,14 @@
// All rights reserved.
// expr-context.go
package expr
package kern
// ----Expression Context
type ExprContext interface {
Clone() ExprContext
SetParent(ctx ExprContext)
GetParent() (ctx ExprContext)
GetGlobal() (ctx ExprContext)
GetVar(varName string) (value any, exists bool)
GetLast() any
SetVar(varName string, value any)
@@ -22,6 +23,7 @@ type ExprContext interface {
FuncCount() int
DeleteFunc(funcName string)
GetLocalFuncInfo(name string) (info ExprFunc, exists bool)
GetFuncInfo(name string) (item ExprFunc, exists bool)
Call(name string, args map[string]any) (result any, err error)
RegisterFuncInfo(info ExprFunc)
+1 -1
View File
@@ -2,7 +2,7 @@
// All rights reserved.
// expr-function.go
package expr
package kern
// ---- Functor interface
type Functor interface {
+2 -2
View File
@@ -2,7 +2,7 @@
// All rights reserved.
// formatter.go
package expr
package kern
import "fmt"
@@ -46,7 +46,7 @@ type Formatter interface {
ToString(options FmtOpt) string
}
func getFormatted(v any, opt FmtOpt) (text string) {
func GetFormatted(v any, opt FmtOpt) (text string) {
if v == nil {
text = "(nil)"
} else if s, ok := v.(string); ok {
+33 -25
View File
@@ -2,7 +2,7 @@
// All rights reserved.
// fraction-type.go
package expr
package kern
//https://www.youmath.it/lezioni/algebra-elementare/lezioni-di-algebra-e-aritmetica-per-scuole-medie/553-dalle-frazioni-a-numeri-decimali.html
@@ -18,12 +18,12 @@ type FractionType struct {
num, den int64
}
func newFraction(num, den int64) *FractionType {
func NewFraction(num, den int64) *FractionType {
num, den = simplifyIntegers(num, den)
return &FractionType{num, den}
}
func float64ToFraction(f float64) (fract *FractionType, err error) {
func Float64ToFraction(f float64) (fract *FractionType, err error) {
var sign string
intPart, decPart := math.Modf(f)
if decPart < 0.0 {
@@ -33,11 +33,11 @@ func float64ToFraction(f float64) (fract *FractionType, err error) {
}
dec := fmt.Sprintf("%.12f", decPart)
s := fmt.Sprintf("%s%.f%s", sign, intPart, dec[1:])
return makeGeneratingFraction(s)
return MakeGeneratingFraction(s)
}
// Based on https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/math/big/rat.go;l=39
func makeGeneratingFraction(s string) (f *FractionType, err error) {
func MakeGeneratingFraction(s string) (f *FractionType, err error) {
var num, den int64
var sign int64 = 1
var parts []string
@@ -59,7 +59,7 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) {
return
}
if len(parts) == 1 {
f = newFraction(sign*num, 1)
f = NewFraction(sign*num, 1)
} else if len(parts) == 2 {
subParts := strings.SplitN(parts[1], "(", 2)
if len(subParts) == 1 {
@@ -76,7 +76,7 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) {
num = num*10 + int64(c-'0')
den = den * 10
}
f = newFraction(sign*num, den)
f = NewFraction(sign*num, den)
} else if len(subParts) == 2 {
sub := num
mul := int64(1)
@@ -103,7 +103,7 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) {
den *= mul
}
num -= sub
f = newFraction(sign*num, den)
f = NewFraction(sign*num, den)
}
}
exit:
@@ -113,7 +113,15 @@ exit:
return
}
func (f *FractionType) toFloat() float64 {
func (f *FractionType) N() int64 {
return f.num
}
func (f *FractionType) D() int64 {
return f.den
}
func (f *FractionType) ToFloat() float64 {
return float64(f.num) / float64(f.den)
}
@@ -168,7 +176,7 @@ func (f *FractionType) TypeName() string {
// -------- fraction utility functions
// greatest common divider
func gcd(a, b int64) (g int64) {
func Gcd(a, b int64) (g int64) {
if a < 0 {
a = -a
}
@@ -189,21 +197,21 @@ func gcd(a, b int64) (g int64) {
// lower common multiple
func lcm(a, b int64) (l int64) {
g := gcd(a, b)
g := Gcd(a, b)
l = a * b / g
return
}
// Sum two fractions
func sumFract(f1, f2 *FractionType) (sum *FractionType) {
func SumFract(f1, f2 *FractionType) (sum *FractionType) {
m := lcm(f1.den, f2.den)
sum = newFraction(f1.num*(m/f1.den)+f2.num*(m/f2.den), m)
sum = NewFraction(f1.num*(m/f1.den)+f2.num*(m/f2.den), m)
return
}
// Multiply two fractions
func mulFract(f1, f2 *FractionType) (prod *FractionType) {
prod = newFraction(f1.num*f2.num, f1.den*f2.den)
func MulFract(f1, f2 *FractionType) (prod *FractionType) {
prod = NewFraction(f1.num*f2.num, f1.den*f2.den)
return
}
@@ -230,12 +238,12 @@ func anyPairToFract(v1, v2 any) (f1, f2 *FractionType, err error) {
return
}
func sumAnyFract(af1, af2 any) (sum any, err error) {
func SumAnyFract(af1, af2 any) (sum any, err error) {
var f1, f2 *FractionType
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
return
}
f := sumFract(f1, f2)
f := SumFract(f1, f2)
if f.num == 0 {
sum = 0
} else {
@@ -250,7 +258,7 @@ func sumAnyFract(af1, af2 any) (sum any, err error) {
// =0 if af1 == af2
// >0 if af1 > af2
// err if af1 or af2 is not convertible to fraction
func cmpAnyFract(af1, af2 any) (result int, err error) {
func CmpAnyFract(af1, af2 any) (result int, err error) {
var f1, f2 *FractionType
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
return
@@ -266,7 +274,7 @@ func cmpAnyFract(af1, af2 any) (result int, err error) {
// >0 if af1 > af2
func cmpFract(f1, f2 *FractionType) (result int) {
f2.num = -f2.num
f := sumFract(f1, f2)
f := SumFract(f1, f2)
if f.num < 0 {
result = -1
} else if f.num > 0 {
@@ -277,13 +285,13 @@ func cmpFract(f1, f2 *FractionType) (result int) {
return
}
func subAnyFract(af1, af2 any) (sum any, err error) {
func SubAnyFract(af1, af2 any) (sum any, err error) {
var f1, f2 *FractionType
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
return
}
f2.num = -f2.num
f := sumFract(f1, f2)
f := SumFract(f1, f2)
if f.num == 0 {
sum = 0
} else {
@@ -292,7 +300,7 @@ func subAnyFract(af1, af2 any) (sum any, err error) {
return
}
func mulAnyFract(af1, af2 any) (prod any, err error) {
func MulAnyFract(af1, af2 any) (prod any, err error) {
var f1, f2 *FractionType
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
return
@@ -306,7 +314,7 @@ func mulAnyFract(af1, af2 any) (prod any, err error) {
return
}
func divAnyFract(af1, af2 any) (quot any, err error) {
func DivAnyFract(af1, af2 any) (quot any, err error) {
var f1, f2 *FractionType
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
return
@@ -345,7 +353,7 @@ func simplifyIntegers(num, den int64) (a, b int64) {
den = -den
num = -num
}
g := gcd(num, den)
g := Gcd(num, den)
a = num / g
b = den / g
return
@@ -355,7 +363,7 @@ func intToFraction(n int64) *FractionType {
return &FractionType{n, 1}
}
func isFraction(v any) (ok bool) {
func IsFraction(v any) (ok bool) {
_, ok = v.(*FractionType)
return ok
}
+273
View File
@@ -0,0 +1,273 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// function.go
package kern
import (
"fmt"
"strconv"
)
// ---- Function templates
type FuncTemplate func(ctx ExprContext, name string, args map[string]any) (result any, err error)
type DeepFuncTemplate func(a, b any) (eq bool, 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(){}"
}
return s
}
func (functor *BaseFunctor) GetParams() (params []ExprFuncParam) {
if functor.info != nil {
return functor.info.Params()
} else {
return []ExprFuncParam{}
}
}
func (functor *BaseFunctor) SetFunc(info ExprFunc) {
functor.info = info
}
func (functor *BaseFunctor) GetFunc() ExprFunc {
return functor.info
}
func (functor *BaseFunctor) GetDefinitionContext() ExprContext {
return nil
}
// ---- Function Parameters
type paramFlags uint16
const (
PfDefault paramFlags = 1 << iota
PfOptional
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 TypeAny
}
func (param *funcParamInfo) IsDefault() bool {
return (param.flags & PfDefault) != 0
}
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
}
func initActualParams(ctx ExprContext, info ExprFunc, callTerm Term) (actualParams map[string]any, err error) {
var varArgs []any
var varName string
namedParamsStarted := false
formalParams := info.Params()
actualParams = make(map[string]any, len(formalParams))
if callTerm == nil {
return
}
childCount := callTerm.GetChildCount()
for i := range childCount {
tree := callTerm.GetChild(i)
// for i, tree := range callTerm.Children() {
var paramValue any
paramCtx := ctx.Clone()
if paramValue, err = tree.Compute(paramCtx); err != nil {
break
}
if paramName, namedParam := GetAssignVarName(tree); namedParam {
if info.ParamSpec(paramName) == nil {
err = fmt.Errorf("%s(): unknown param %q", info.Name(), paramName)
break
}
actualParams[paramName] = paramValue
namedParamsStarted = true
} else if !namedParamsStarted {
if varArgs != nil {
varArgs = append(varArgs, paramValue)
} else if i < len(formalParams) {
spec := formalParams[i]
if spec.IsRepeat() {
varArgs = make([]any, 0, childCount-i)
varArgs = append(varArgs, paramValue)
varName = spec.Name()
} else {
actualParams[spec.Name()] = paramValue
}
} else {
err = ErrTooManyParams(info.Name(), len(formalParams), childCount)
break
}
} else {
err = fmt.Errorf("%s(): positional param nr %d not allowed after named params", info.Name(), i+1)
break
}
}
if err == nil {
if varArgs != nil {
actualParams[varName] = varArgs
}
}
return
}
// func (info *funcInfo) PrepareCall(name string, actualParams map[string]any) (err error) {
// passedCount := len(actualParams)
// if info.MinArgs() > passedCount {
// err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
// return
// }
// if passedCount < len(info.formalParams) {
// for _, p := range info.formalParams {
// if _, exists := actualParams[p.Name()]; !exists {
// if !p.IsDefault() {
// break
// }
// if p.IsRepeat() {
// varArgs := make([]any, 1)
// varArgs[0] = p.DefaultValue()
// actualParams[p.Name()] = varArgs
// } else {
// actualParams[p.Name()] = p.DefaultValue()
// }
// }
// }
// }
// if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) {
// err = ErrTooManyParams(name, info.MaxArgs(), len(actualParams))
// }
// return
// }
// ----- Call a function ---
// func getAssignVarName(t *term) (name string, ok bool) {
// if ok = t.symbol() == SymEqual; ok {
// name = t.children[0].source()
// }
// return
// }
func GetAssignVarName(t Term) (name string, ok bool) {
if ok = t.IsAssign(); ok {
name = t.GetChildSource(0)
}
return
}
func CallFunctionByTerm(parentCtx ExprContext, name string, callTerm Term) (result any, err error) {
var actualParams map[string]any
if info, exists := parentCtx.GetFuncInfo(name); exists {
if actualParams, err = initActualParams(parentCtx, info, callTerm); err == nil {
ctx := info.AllocContext(parentCtx)
if err = info.PrepareCall(name, actualParams); err == nil {
functor := info.Functor()
result, err = functor.InvokeNamed(ctx, name, actualParams)
exportObjectsToParent(ctx)
}
}
} else {
err = fmt.Errorf("unknown function %s()", name)
}
return
}
func CallFunctionByArgs(parentCtx ExprContext, name string, args []any) (result any, err error) {
var actualParams map[string]any
if info, exists := parentCtx.GetFuncInfo(name); exists {
functor := info.Functor()
actualParams = BindActualParams(functor, args)
ctx := info.AllocContext(parentCtx)
if err = info.PrepareCall(name, actualParams); err == nil {
result, err = functor.InvokeNamed(ctx, name, actualParams)
exportObjectsToParent(ctx)
}
} else {
err = fmt.Errorf("unknown function %s()", name)
}
return
}
func CallFunctionByParams(parentCtx ExprContext, name string, actualParams map[string]any) (result any, err error) {
//var actualParams map[string]any
if info, exists := parentCtx.GetFuncInfo(name); exists {
functor := info.Functor()
ctx := info.AllocContext(parentCtx)
if err = info.PrepareCall(name, actualParams); err == nil {
result, err = functor.InvokeNamed(ctx, name, actualParams)
exportObjectsToParent(ctx)
}
} else {
err = fmt.Errorf("unknown function %s()", name)
}
return
}
func GetParam(args map[string]any, paramName string, paramNum int) (value any, exists bool) {
if value, exists = args[paramName]; !exists {
if paramNum > 0 && paramNum <= len(args) {
value, exists = args["arg"+strconv.Itoa(paramNum)]
}
}
return
}
func BindActualParams(functor Functor, args []any) (actualParams map[string]any) {
formalParams := functor.GetParams()
actualParams = make(map[string]any, len(args))
for i, arg := range args {
if i < len(formalParams) {
actualParams[formalParams[i].Name()] = arg
} else {
actualParams["arg"+strconv.Itoa(i+1)] = arg
}
}
return
}
+7 -8
View File
@@ -2,7 +2,7 @@
// All rights reserved.
// iterator.go
package expr
package kern
import (
// "errors"
@@ -21,28 +21,27 @@ const (
CountName = "count"
FilterName = "filter"
MapName = "map"
KeyName = "key"
ValueName = "value"
)
type Iterator interface {
Typer
fmt.Stringer
Next() (item any, err error) // must return io.EOF after the last item
Current() (item any, err error)
Index() int
Count() int
HasOperation(name string) bool
CallOperation(name string, args map[string]any) (value any, err error)
}
type ExtIterator interface {
Iterator
Reset() error
Clean() error
HasOperation(name string) bool
CallOperation(name string, args map[string]any) (value any, err error)
}
func errNoOperation(name string) error {
func ErrNoOperation(name string) error {
return fmt.Errorf("no %s() function defined in the data-source", name)
}
// func errInvalidDataSource() error {
// return errors.New("invalid data-source")
// }
+30 -31
View File
@@ -2,7 +2,7 @@
// All rights reserved.
// list-type.go
package expr
package kern
import (
"fmt"
@@ -12,23 +12,16 @@ import (
type ListType []any
func newListA(listAny ...any) (list *ListType) {
func NewListA(listAny ...any) (list *ListType) {
if listAny == nil {
listAny = []any{}
}
return newList(listAny)
}
func newList(listAny []any) (list *ListType) {
return NewList(listAny)
}
func NewList(listAny []any) (list *ListType) {
if listAny != nil {
ls := make(ListType, len(listAny))
// for i, item := range listAny {
// ls[i] = item
// }
copy(ls, listAny)
list = &ls
}
@@ -106,22 +99,11 @@ func (ls *ListType) TypeName() string {
return "list"
}
// func (list *ListType) indexDeepCmp(target any) (index int) {
// index = -1
// for i, item := range *list {
// if reflect.DeepEqual(item, target) {
// index = i
// break
// }
// }
// return
// }
func (ls *ListType) contains(t *ListType) (answer bool) {
func (ls *ListType) Contains(t *ListType) (answer bool) {
if len(*ls) >= len(*t) {
answer = true
for _, item := range *t {
if answer = ls.indexDeepSameCmp(item) >= 0; !answer {
if answer = ls.IndexDeepSameCmp(item) >= 0; !answer {
break
}
}
@@ -129,12 +111,26 @@ func (ls *ListType) contains(t *ListType) (answer bool) {
return
}
func (list *ListType) indexDeepSameCmp(target any) (index int) {
func (ls1 *ListType) Equals(ls2 ListType) (answer bool) {
if ls2 != nil && len(*ls1) == len(ls2) {
answer = true
for index, i1 := range *ls1 {
// if i1 != (ls2)[index] {
if !reflect.DeepEqual(i1, ls2[index]) {
answer = false
break
}
}
}
return
}
func (list *ListType) IndexDeepSameCmp(target any) (index int) {
var eq bool
var err error
index = -1
for i, item := range *list {
if eq, err = deepSame(item, target, sameContent); err != nil {
if eq, err = deepSame(item, target, SameContent); err != nil {
break
} else if eq {
index = i
@@ -144,13 +140,13 @@ func (list *ListType) indexDeepSameCmp(target any) (index int) {
return
}
func sameContent(a, b any) (same bool, err error) {
func SameContent(a, b any) (same bool, err error) {
la, _ := a.(*ListType)
lb, _ := b.(*ListType)
if len(*la) == len(*lb) {
same = true
for _, item := range *la {
if pos := lb.indexDeepSameCmp(item); pos < 0 {
if pos := lb.IndexDeepSameCmp(item); pos < 0 {
same = false
break
}
@@ -159,19 +155,19 @@ func sameContent(a, b any) (same bool, err error) {
return
}
func deepSame(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) {
if isNumOrFract(a) && isNumOrFract(b) {
func deepSame(a, b any, deepCmp DeepFuncTemplate) (eq bool, err error) {
if IsNumOrFract(a) && IsNumOrFract(b) {
if IsNumber(a) && IsNumber(b) {
if IsInteger(a) && IsInteger(b) {
li, _ := a.(int64)
ri, _ := b.(int64)
eq = li == ri
} else {
eq = numAsFloat(a) == numAsFloat(b)
eq = NumAsFloat(a) == NumAsFloat(b)
}
} else {
var cmp int
if cmp, err = cmpAnyFract(a, b); err == nil {
if cmp, err = CmpAnyFract(a, b); err == nil {
eq = cmp == 0
}
}
@@ -184,7 +180,7 @@ func deepSame(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) {
return
}
func (list *ListType) setItem(index int64, value any) (err error) {
func (list *ListType) SetItem(index int64, value any) (err error) {
if index >= 0 && index < int64(len(*list)) {
(*list)[index] = value
} else {
@@ -193,3 +189,6 @@ func (list *ListType) setItem(index int64, value any) (err error) {
return
}
func (list *ListType) AppendItem(value any) {
*list = append(*list, value)
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// term.go
package kern
import (
"fmt"
)
type Term interface {
fmt.Stringer
// Children() []Term
Source() string
GetChildCount() (count int)
GetChild(index int) Term
GetChildSource(index int) string
Compute(ctx ExprContext) (result any, err error)
IsAssign() bool
Errorf(template string, args ...any) (err error)
}
+48
View File
@@ -0,0 +1,48 @@
//go:build unix
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// utils-unix.go
package kern
import (
"os"
"os/user"
"path"
"strings"
)
func ExpandPath(sourcePath string) (expandedPath string, err error) {
for expandedPath = os.ExpandEnv(sourcePath); expandedPath != sourcePath; expandedPath = os.ExpandEnv(sourcePath) {
sourcePath = expandedPath
}
if strings.HasPrefix(sourcePath, "~") {
var home, userName, remainder string
slashPos := strings.IndexRune(sourcePath, '/')
if slashPos > 0 {
userName = sourcePath[1:slashPos]
remainder = sourcePath[slashPos:]
} else {
userName = sourcePath[1:]
}
if len(userName) == 0 {
home, err = os.UserHomeDir()
if err != nil {
return
}
} else {
var userInfo *user.User
userInfo, err = user.Lookup(userName)
if err != nil {
return
}
home = userInfo.HomeDir
}
expandedPath = path.Join(home, remainder)
}
return
}
+18
View File
@@ -0,0 +1,18 @@
//go:build windows
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// utils-unix.go
package kern
import (
"os"
)
func ExpandPath(sourcePath string) (expandedPath string, err error) {
for expandedPath = os.ExpandEnv(sourcePath); expandedPath != sourcePath; expandedPath = os.ExpandEnv(sourcePath) {
sourcePath = expandedPath
}
return
}
+23 -52
View File
@@ -2,15 +2,11 @@
// All rights reserved.
// utils.go
package expr
package kern
import (
"fmt"
"os"
"os/user"
"path"
"reflect"
"strings"
)
func IsString(v any) (ok bool) {
@@ -59,29 +55,29 @@ func IsNumber(v any) (ok bool) {
return IsFloat(v) || IsInteger(v)
}
func isNumOrFract(v any) (ok bool) {
return IsFloat(v) || IsInteger(v) || isFraction(v)
func IsNumOrFract(v any) (ok bool) {
return IsFloat(v) || IsInteger(v) || IsFraction(v)
}
func isNumberString(v any) (ok bool) {
func IsNumberString(v any) (ok bool) {
return IsString(v) || IsNumber(v)
}
func isFunctor(v any) (ok bool) {
func IsFunctor(v any) (ok bool) {
_, ok = v.(Functor)
return
}
func isIterator(v any) (ok bool) {
func IsIterator(v any) (ok bool) {
_, ok = v.(Iterator)
return
}
func numAsFloat(v any) (f float64) {
func NumAsFloat(v any) (f float64) {
var ok bool
if f, ok = v.(float64); !ok {
if fract, ok := v.(*FractionType); ok {
f = fract.toFloat()
f = fract.ToFloat()
} else {
i, _ := v.(int64)
f = float64(i)
@@ -107,11 +103,11 @@ func ToBool(v any) (b bool, ok bool) {
return
}
func isFunc(v any) bool {
func IsFunc(v any) bool {
return reflect.TypeOf(v).Kind() == reflect.Func
}
func anyInteger(v any) (i int64, ok bool) {
func AnyInteger(v any) (i int64, ok bool) {
ok = true
switch intval := v.(type) {
case int:
@@ -138,7 +134,7 @@ func anyInteger(v any) (i int64, ok bool) {
return
}
func fromGenericAny(v any) (exprAny any, ok bool) {
func FromGenericAny(v any) (exprAny any, ok bool) {
if v != nil {
if exprAny, ok = v.(bool); ok {
return
@@ -146,10 +142,10 @@ func fromGenericAny(v any) (exprAny any, ok bool) {
if exprAny, ok = v.(string); ok {
return
}
if exprAny, ok = anyInteger(v); ok {
if exprAny, ok = AnyInteger(v); ok {
return
}
if exprAny, ok = anyFloat(v); ok {
if exprAny, ok = AnyFloat(v); ok {
return
}
if exprAny, ok = v.(*DictType); ok {
@@ -162,7 +158,7 @@ func fromGenericAny(v any) (exprAny any, ok bool) {
return
}
func anyFloat(v any) (float float64, ok bool) {
func AnyFloat(v any) (float float64, ok bool) {
ok = true
switch floatval := v.(type) {
case float32:
@@ -218,6 +214,15 @@ func ToGoInt(value any, description string) (i int, err error) {
return
}
func ToGoString(value any, description string) (s string, err error) {
if s, ok := value.(string); ok {
return s, nil
} else {
err = fmt.Errorf("%s expected string, got %s (%v)", description, TypeName(value), value)
}
return
}
func ForAll[T, V any](ts []T, fn func(T) V) []V {
result := make([]V, len(ts))
for i, t := range ts {
@@ -225,37 +230,3 @@ func ForAll[T, V any](ts []T, fn func(T) V) []V {
}
return result
}
func ExpandPath(sourcePath string) (expandedPath string, err error) {
for expandedPath = os.ExpandEnv(sourcePath); expandedPath != sourcePath; expandedPath = os.ExpandEnv(sourcePath) {
sourcePath = expandedPath
}
if strings.HasPrefix(sourcePath, "~") {
var home, userName, remainder string
slashPos := strings.IndexRune(sourcePath, '/')
if slashPos > 0 {
userName = sourcePath[1:slashPos]
remainder = sourcePath[slashPos:]
} else {
userName = sourcePath[1:]
}
if len(userName) == 0 {
home, err = os.UserHomeDir()
if err != nil {
return
}
} else {
var userInfo *user.User
userInfo, err = user.Lookup(userName)
if err != nil {
return
}
home = userInfo.HomeDir
}
expandedPath = path.Join(home, remainder)
}
return
}
+9
View File
@@ -0,0 +1,9 @@
//go:build darwin
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// lib-ext-darwin.go
package expr
const SHAREDLIBRARY_EXTENSION = ".dylib"
+9
View File
@@ -0,0 +1,9 @@
//go:build linux
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// lib-ext-linux.go
package expr
const SHAREDLIBRARY_EXTENSION = ".so"
+9
View File
@@ -0,0 +1,9 @@
//go:build windows
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// lib-ext-windows.go
package expr
const SHAREDLIBRARY_EXTENSION = ".dll"
+21 -32
View File
@@ -7,10 +7,13 @@ package expr
import (
"fmt"
"io"
"slices"
"git.portale-stac.it/go-pkg/expr/kern"
)
type ListIterator struct {
a *ListType
a *kern.ListType
count int
index int
start int
@@ -18,7 +21,7 @@ type ListIterator struct {
step int
}
func NewListIterator(list *ListType, args []any) (it *ListIterator) {
func NewListIterator(list *kern.ListType, args []any) (it *ListIterator) {
var argc int = 0
listLen := len(([]any)(*list))
if args != nil {
@@ -26,21 +29,21 @@ func NewListIterator(list *ListType, args []any) (it *ListIterator) {
}
it = &ListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1}
if argc >= 1 {
if i, err := ToGoInt(args[0], "start index"); err == nil {
if i, err := kern.ToGoInt(args[0], "start index"); err == nil {
if i < 0 {
i = listLen + i
}
it.start = i
}
if argc >= 2 {
if i, err := ToGoInt(args[1], "stop index"); err == nil {
if i, err := kern.ToGoInt(args[1], "stop index"); err == nil {
if i < 0 {
i = listLen + i
}
it.stop = i
}
if argc >= 3 {
if i, err := ToGoInt(args[2], "step"); err == nil {
if i, err := kern.ToGoInt(args[2], "step"); err == nil {
if i < 0 {
i = -i
}
@@ -58,22 +61,7 @@ func NewListIterator(list *ListType, args []any) (it *ListIterator) {
}
func NewArrayIterator(array []any) (it *ListIterator) {
it = &ListIterator{a: (*ListType)(&array), count: 0, index: -1, start: 0, stop: len(array) - 1, step: 1}
return
}
func NewAnyIterator(value any) (it *ListIterator) {
if value == nil {
it = NewArrayIterator([]any{})
} else if list, ok := value.(*ListType); ok {
it = NewListIterator(list, nil)
} else if array, ok := value.([]any); ok {
it = NewArrayIterator(array)
} else if it1, ok := value.(*ListIterator); ok {
it = it1
} else {
it = NewArrayIterator([]any{value})
}
it = &ListIterator{a: (*kern.ListType)(&array), count: 0, index: -1, start: 0, stop: len(array) - 1, step: 1}
return
}
@@ -82,7 +70,7 @@ func (it *ListIterator) String() string {
if it.a != nil {
l = len(*it.a)
}
return fmt.Sprintf("$(#%d)", l)
return fmt.Sprintf("$([#%d])", l)
}
func (it *ListIterator) TypeName() string {
@@ -90,26 +78,27 @@ func (it *ListIterator) TypeName() string {
}
func (it *ListIterator) HasOperation(name string) bool {
yes := name == NextName || name == ResetName || name == IndexName || name == CountName || name == CurrentName
//yes := name == expr.NextName || name == expr.ResetName || name == expr.IndexName || name == expr.CountName || name == expr.CurrentName
yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName}, name)
return yes
}
func (it *ListIterator) CallOperation(name string, args map[string]any) (v any, err error) {
switch name {
case NextName:
case kern.NextName:
v, err = it.Next()
case ResetName:
case kern.ResetName:
err = it.Reset()
case CleanName:
case kern.CleanName:
err = it.Clean()
case IndexName:
case kern.IndexName:
v = int64(it.Index())
case CurrentName:
case kern.CurrentName:
v, err = it.Current()
case CountName:
case kern.CountName:
v = it.count
default:
err = errNoOperation(name)
err = kern.ErrNoOperation(name)
}
return
}
@@ -149,12 +138,12 @@ func (it *ListIterator) Count() int {
return it.count
}
func (it *ListIterator) Reset() (error) {
func (it *ListIterator) Reset() error {
it.index = it.start - it.step
it.count = 0
return nil
}
func (it *ListIterator) Clean() (error) {
func (it *ListIterator) Clean() error {
return nil
}
+6 -3
View File
@@ -4,6 +4,9 @@
// operand-dict.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- dict term
func newDictTerm(args map[any]*term) *term {
@@ -18,12 +21,12 @@ func newDictTerm(args map[any]*term) *term {
}
// -------- dict func
func evalDict(ctx ExprContext, opTerm *term) (v any, err error) {
func evalDict(ctx kern.ExprContext, opTerm *term) (v any, err error) {
dict, _ := opTerm.value().(map[any]*term)
items := make(DictType, len(dict))
items := make(kern.DictType, len(dict))
for key, tree := range dict {
var param any
if param, err = tree.compute(ctx); err != nil {
if param, err = tree.Compute(ctx); err != nil {
break
}
items[key] = param
+9 -5
View File
@@ -4,11 +4,15 @@
// operand-expr.go
package expr
import "fmt"
import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- expr term
func newExprTerm(root *term) *term {
tk := NewValueToken(root.tk.row, root.tk.col, SymExpression, root.source(), root)
tk := NewValueToken(root.tk.row, root.tk.col, SymExpression, root.Source(), root)
return &term{
tk: *tk,
parent: nil,
@@ -20,9 +24,9 @@ func newExprTerm(root *term) *term {
}
// -------- eval expr
func evalExpr(ctx ExprContext, opTerm *term) (v any, err error) {
if expr, ok := opTerm.value().(*term); ok {
v, err = expr.compute(ctx)
func evalExpr(ctx kern.ExprContext, opTerm *term) (v any, err error) {
if ast, ok := opTerm.value().(*term); ok {
v, err = ast.Compute(ctx)
} else {
err = fmt.Errorf("expression expected, got %T", opTerm.value())
}
+15 -9
View File
@@ -6,15 +6,21 @@ package expr
import (
"errors"
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- function call term
func newFuncCallTerm(tk *Token, args []*term) *term {
var pos termPosition = posLeaf
if len(args) > 0 {
pos = posMultifix
}
return &term{
tk: *tk,
parent: nil,
children: args,
position: posLeaf,
position: pos,
priority: priValue,
evalFunc: evalFuncCall,
}
@@ -38,9 +44,9 @@ func newFuncCallTerm(tk *Token, args []*term) *term {
// return
// }
func evalFuncCall(ctx ExprContext, opTerm *term) (v any, err error) {
func evalFuncCall(ctx kern.ExprContext, opTerm *term) (v any, err error) {
name, _ := opTerm.tk.Value.(string)
v, err = CallFunctionByTerm(ctx, name, opTerm)
v, err = kern.CallFunctionByTerm(ctx, name, opTerm)
return
}
@@ -57,23 +63,23 @@ func newFuncDefTerm(tk *Token, args []*term) *term {
}
// -------- eval func def
func evalFuncDef(ctx ExprContext, opTerm *term) (v any, err error) {
func evalFuncDef(ctx kern.ExprContext, opTerm *term) (v any, err error) {
bodySpec := opTerm.value()
if expr, ok := bodySpec.(*ast); ok {
paramList := make([]ExprFuncParam, 0, len(opTerm.children))
if ast, ok := bodySpec.(*ast); ok {
paramList := make([]kern.ExprFuncParam, 0, len(opTerm.children))
for _, param := range opTerm.children {
var defValue any
flags := paramFlags(0)
if len(param.children) > 0 {
flags |= PfDefault
if defValue, err = param.children[0].compute(ctx); err != nil {
if defValue, err = param.children[0].Compute(ctx); err != nil {
return
}
}
info := NewFuncParamFlagDef(param.source(), flags, defValue)
info := NewFuncParamFlagDef(param.Source(), flags, defValue)
paramList = append(paramList, info)
}
v = newExprFunctor(expr, paramList, ctx)
v = newExprFunctor(ast, paramList, ctx)
} else {
err = errors.New("invalid function definition: the body specification must be an expression")
}
+33 -19
View File
@@ -7,6 +7,8 @@ package expr
import (
"slices"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- iterator term
@@ -25,11 +27,11 @@ func newIteratorTerm(tk *Token, args []*term) *term {
// -------- eval iterator
func evalTermArray(ctx ExprContext, terms []*term) (values []any, err error) {
func evalTermArray(ctx kern.ExprContext, terms []*term) (values []any, err error) {
values = make([]any, len(terms))
for i, t := range terms {
var value any
if value, err = t.compute(ctx); err == nil {
if value, err = t.Compute(ctx); err == nil {
values[i] = value
} else {
break
@@ -38,25 +40,25 @@ func evalTermArray(ctx ExprContext, terms []*term) (values []any, err error) {
return
}
func evalFirstChild(ctx ExprContext, iteratorTerm *term) (value any, err error) {
func evalFirstChild(ctx kern.ExprContext, iteratorTerm *term) (value any, err error) {
if len(iteratorTerm.children) < 1 || iteratorTerm.children[0] == nil {
err = iteratorTerm.Errorf("missing the data-source parameter")
return
}
value, err = iteratorTerm.children[0].compute(ctx)
value, err = iteratorTerm.children[0].Compute(ctx)
return
}
func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]Functor, err error) {
if dictAny, ok := firstChildValue.(*DictType); ok {
requiredFields := []string{NextName}
func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]kern.Functor, err error) {
if dictAny, ok := firstChildValue.(*kern.DictType); ok {
requiredFields := []string{kern.NextName}
fieldsMask := 0b1
foundFields := 0
ds = make(map[string]Functor)
ds = make(map[string]kern.Functor)
for keyAny, item := range *dictAny {
if key, ok := keyAny.(string); ok {
if functor, ok := item.(Functor); ok {
if functor, ok := item.(kern.Functor); ok {
ds[key] = functor
if index := slices.Index(requiredFields, key); index >= 0 {
foundFields |= 1 << index
@@ -78,22 +80,24 @@ func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]F
return
}
func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
func evalIterator(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var firstChildValue any
var ds map[string]Functor
var ds map[string]kern.Functor
if firstChildValue, err = evalFirstChild(ctx, opTerm); err != nil {
return
}
if ds, err = getDataSourceDict(opTerm, firstChildValue); err != nil {
if ds, err = getDataSourceDict(opTerm, firstChildValue); err != nil && ds == nil {
return
}
err = nil
if ds != nil {
if len(ds) > 0 {
var dc *dataCursor
dcCtx := ctx.Clone()
if initFunc, exists := ds[InitName]; exists && initFunc != nil {
if initFunc, exists := ds[kern.InitName]; exists && initFunc != nil {
var args []any
var resource any
if len(opTerm.children) > 1 {
@@ -104,20 +108,30 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
args = []any{}
}
actualParams := bindActualParams(initFunc, args)
actualParams := kern.BindActualParams(initFunc, args)
initCtx := ctx.Clone()
if resource, err = initFunc.InvokeNamed(initCtx, InitName, actualParams); err != nil {
if resource, err = initFunc.InvokeNamed(initCtx, kern.InitName, actualParams); err != nil {
return
}
exportObjects(dcCtx, initCtx)
kern.ExportObjects(dcCtx, initCtx)
dc = NewDataCursor(dcCtx, ds, resource)
} else {
dc = NewDataCursor(dcCtx, ds, nil)
}
v = dc
} else if list, ok := firstChildValue.(*ListType); ok {
} else {
if dictIt, ok := firstChildValue.(*kern.DictType); ok {
var args []any
if args, err = evalSibling(ctx, opTerm.children, nil); err == nil {
v, err = NewDictIterator(dictIt, args)
}
} else {
err = opTerm.children[0].Errorf("the data-source must be a dictionary")
}
}
} else if list, ok := firstChildValue.(*kern.ListType); ok {
var args []any
if args, err = evalSibling(ctx, opTerm.children, nil); err == nil {
v = NewListIterator(list, args)
@@ -131,7 +145,7 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
return
}
func evalSibling(ctx ExprContext, terms []*term, firstChildValue any) (list []any, err error) {
func evalSibling(ctx kern.ExprContext, terms []*term, firstChildValue any) (list []any, err error) {
items := make([]any, 0, len(terms))
for i, tree := range terms {
var param any
@@ -140,7 +154,7 @@ func evalSibling(ctx ExprContext, terms []*term, firstChildValue any) (list []an
continue
}
param = firstChildValue
} else if param, err = tree.compute(ctx); err != nil {
} else if param, err = tree.Compute(ctx); err != nil {
break
}
items = append(items, param)
+7 -3
View File
@@ -4,6 +4,10 @@
// operand-list.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- list term
func newListTermA(args ...*term) *term {
return newListTerm(0, 0, args)
@@ -21,12 +25,12 @@ func newListTerm(row, col int, args []*term) *term {
}
// -------- list func
func evalList(ctx ExprContext, opTerm *term) (v any, err error) {
func evalList(ctx kern.ExprContext, opTerm *term) (v any, err error) {
list, _ := opTerm.value().([]*term)
items := make(ListType, len(list))
items := make(kern.ListType, len(list))
for i, tree := range list {
var param any
if param, err = tree.compute(ctx); err != nil {
if param, err = tree.Compute(ctx); err != nil {
break
}
items[i] = param
+5 -1
View File
@@ -4,6 +4,10 @@
// operand-literal.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- literal term
func newLiteralTerm(tk *Token) *term {
return &term{
@@ -17,7 +21,7 @@ func newLiteralTerm(tk *Token) *term {
}
// -------- eval func
func evalLiteral(ctx ExprContext, opTerm *term) (v any, err error) {
func evalLiteral(ctx kern.ExprContext, opTerm *term) (v any, err error) {
v = opTerm.tk.Value
return
}
+3 -1
View File
@@ -7,6 +7,8 @@ package expr
import (
"fmt"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- selector case term
@@ -41,7 +43,7 @@ func newSelectorCaseTerm(row, col int, filterList *term, caseExpr Expr) *term {
}
// -------- eval selector case
func evalSelectorCase(ctx ExprContext, opTerm *term) (v any, err error) {
func evalSelectorCase(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var ok bool
if v, ok = opTerm.value().(*selectorCase); !ok {
err = fmt.Errorf("selector-case expected, got %T", opTerm.value())
+9 -5
View File
@@ -4,7 +4,11 @@
// operand-var.go
package expr
import "fmt"
import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- variable term
func newVarTerm(tk *Token) *term {
@@ -21,11 +25,11 @@ func newVarTerm(tk *Token) *term {
}
// -------- eval func
func evalVar(ctx ExprContext, opTerm *term) (v any, err error) {
func evalVar(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var exists bool
name := opTerm.source()
if v, exists = GetVar(ctx, name); !exists {
if info, exists := GetFuncInfo(ctx, name); exists {
name := opTerm.Source()
if v, exists = ctx.GetVar(name); !exists {
if info, exists := ctx.GetFuncInfo(name); exists {
v = info.Functor()
} else {
err = fmt.Errorf("undefined variable or function %q", name)
+54 -34
View File
@@ -4,6 +4,10 @@
// operator-assign.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- assign term
func newAssignTerm(tk *Token) (inst *term) {
@@ -16,19 +20,19 @@ func newAssignTerm(tk *Token) (inst *term) {
}
}
func assignCollectionItem(ctx ExprContext, collectionTerm, keyListTerm *term, value any) (err error) {
func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *term, value any) (err error) {
var collectionValue, keyListValue, keyValue any
var keyList *ListType
var keyList *kern.ListType
var ok bool
if collectionValue, err = collectionTerm.compute(ctx); err != nil {
if collectionValue, err = collectionTerm.Compute(ctx); err != nil {
return
}
if keyListValue, err = keyListTerm.compute(ctx); err != nil {
if keyListValue, err = keyListTerm.Compute(ctx); err != nil {
return
} else if keyList, ok = keyListValue.(*ListType); !ok || len(*keyList) != 1 {
err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, TypeName(keyListValue))
} else if keyList, ok = keyListValue.(*kern.ListType); !ok || len(*keyList) != 1 {
err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, kern.TypeName(keyListValue))
return
}
if keyValue = (*keyList)[0]; keyValue == nil {
@@ -37,30 +41,30 @@ func assignCollectionItem(ctx ExprContext, collectionTerm, keyListTerm *term, va
}
switch collection := collectionValue.(type) {
case *ListType:
case *kern.ListType:
if index, ok := keyValue.(int64); ok {
err = collection.setItem(index, value)
err = collection.SetItem(index, value)
} else {
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, TypeName(keyValue))
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue))
}
case *DictType:
err = collection.setItem(keyValue, value)
case *kern.DictType:
err = collection.SetItem(keyValue, value)
default:
err = collectionTerm.Errorf("collection expected")
}
return
}
func assignValue(ctx ExprContext, leftTerm *term, v any) (err error) {
func assignValue(ctx kern.ExprContext, leftTerm *term, v any) (err error) {
if leftTerm.symbol() == SymIndex {
err = assignCollectionItem(ctx, leftTerm.children[0], leftTerm.children[1], v)
} else {
ctx.UnsafeSetVar(leftTerm.source(), v)
ctx.UnsafeSetVar(leftTerm.Source(), v)
}
return
}
func evalAssign(ctx ExprContext, opTerm *term) (v any, err error) {
func evalAssign(ctx kern.ExprContext, opTerm *term) (v any, err error) {
if err = opTerm.checkOperands(); err != nil {
return
}
@@ -74,17 +78,17 @@ func evalAssign(ctx ExprContext, opTerm *term) (v any, err error) {
rightChild := opTerm.children[1]
if v, err = rightChild.compute(ctx); err == nil {
if functor, ok := v.(Functor); ok {
if v, err = rightChild.Compute(ctx); err == nil {
if functor, ok := v.(kern.Functor); ok {
if leftSym == SymVariable {
if info := functor.GetFunc(); info != nil {
ctx.RegisterFunc(leftTerm.source(), info.Functor(), info.ReturnType(), info.Params())
ctx.RegisterFunc(leftTerm.Source(), info.Functor(), info.ReturnType(), info.Params())
} else if funcDef, ok := functor.(*exprFunctor); ok {
paramSpecs := ForAll(funcDef.params, func(p ExprFuncParam) ExprFuncParam { return p })
paramSpecs := kern.ForAll(funcDef.params, func(p kern.ExprFuncParam) kern.ExprFuncParam { return p })
ctx.RegisterFunc(leftTerm.source(), functor, TypeAny, paramSpecs)
ctx.RegisterFunc(leftTerm.Source(), functor, kern.TypeAny, paramSpecs)
} else {
err = opTerm.Errorf("unknown function %s()", rightChild.source())
err = opTerm.Errorf("unknown function %s()", rightChild.Source())
}
} else {
err = assignValue(ctx, leftTerm, v)
@@ -111,19 +115,19 @@ func newOpAssignTerm(tk *Token) (inst *term) {
}
}
func getCollectionItemValue(ctx ExprContext, collectionTerm, keyListTerm *term) (value any, err error) {
func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *term) (value any, err error) {
var collectionValue, keyListValue, keyValue any
var keyList *ListType
var keyList *kern.ListType
var ok bool
if collectionValue, err = collectionTerm.compute(ctx); err != nil {
if collectionValue, err = collectionTerm.Compute(ctx); err != nil {
return
}
if keyListValue, err = keyListTerm.compute(ctx); err != nil {
if keyListValue, err = keyListTerm.Compute(ctx); err != nil {
return
} else if keyList, ok = keyListValue.(*ListType); !ok || len(*keyList) != 1 {
err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, TypeName(keyListValue))
} else if keyList, ok = keyListValue.(*kern.ListType); !ok || len(*keyList) != 1 {
err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, kern.TypeName(keyListValue))
return
}
if keyValue = (*keyList)[0]; keyValue == nil {
@@ -132,13 +136,13 @@ func getCollectionItemValue(ctx ExprContext, collectionTerm, keyListTerm *term)
}
switch collection := collectionValue.(type) {
case *ListType:
case *kern.ListType:
if index, ok := keyValue.(int64); ok {
value = (*collection)[index]
} else {
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, TypeName(keyValue))
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue))
}
case *DictType:
case *kern.DictType:
value = (*collection)[keyValue]
default:
err = collectionTerm.Errorf("collection expected")
@@ -146,16 +150,16 @@ func getCollectionItemValue(ctx ExprContext, collectionTerm, keyListTerm *term)
return
}
func getAssignValue(ctx ExprContext, leftTerm *term) (value any, err error) {
func getAssignValue(ctx kern.ExprContext, leftTerm *term) (value any, err error) {
if leftTerm.symbol() == SymIndex {
value, err = getCollectionItemValue(ctx, leftTerm.children[0], leftTerm.children[1])
} else {
value, _ = ctx.GetVar(leftTerm.source())
value, _ = ctx.GetVar(leftTerm.Source())
}
return
}
func evalOpAssign(ctx ExprContext, opTerm *term) (v any, err error) {
func evalOpAssign(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var rightValue, leftValue any
if err = opTerm.checkOperands(); err != nil {
return
@@ -170,7 +174,7 @@ func evalOpAssign(ctx ExprContext, opTerm *term) (v any, err error) {
rightChild := opTerm.children[1]
if rightValue, err = rightChild.compute(ctx); err == nil {
if rightValue, err = rightChild.Compute(ctx); err == nil {
if leftValue, err = getAssignValue(ctx, leftTerm); err == nil {
switch opTerm.symbol() {
case SymPlusEqual:
@@ -183,8 +187,18 @@ func evalOpAssign(ctx ExprContext, opTerm *term) (v any, err error) {
v, err = divValues(opTerm, leftValue, rightValue)
case SymPercEqual:
v, err = remainderValues(opTerm, leftValue, rightValue)
case SymAmpersandEqual:
v, err = bitwiseAnd(opTerm, leftValue, rightValue)
case SymVertBarEqual:
v, err = bitwiseOr(opTerm, leftValue, rightValue)
case SymCaretEqual:
v, err = bitwiseXor(opTerm, leftValue, rightValue)
case SymDoubleLessEqual:
v, err = bitLeftShift(opTerm, leftValue, rightValue)
case SymDoubleGreaterEqual:
v, err = bitRightShift(opTerm, leftValue, rightValue)
default:
err = opTerm.Errorf("unsupported assign operator %q", opTerm.source())
err = opTerm.Errorf("unsupported assign operator %q", opTerm.Source())
}
if err == nil {
err = assignValue(ctx, leftTerm, v)
@@ -201,4 +215,10 @@ func init() {
registerTermConstructor(SymMinusEqual, newOpAssignTerm)
registerTermConstructor(SymStarEqual, newOpAssignTerm)
registerTermConstructor(SymSlashEqual, newOpAssignTerm)
registerTermConstructor(SymPercEqual, newOpAssignTerm)
registerTermConstructor(SymDoubleLessEqual, newOpAssignTerm)
registerTermConstructor(SymDoubleGreaterEqual, newOpAssignTerm)
registerTermConstructor(SymAmpersandEqual, newOpAssignTerm)
registerTermConstructor(SymVertBarEqual, newOpAssignTerm)
registerTermConstructor(SymCaretEqual, newOpAssignTerm)
}
-104
View File
@@ -1,104 +0,0 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-binary.go
package expr
//-------- NOT term
func newBinNotTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priBinNot,
evalFunc: evalBinaryNot,
}
}
func evalBinaryNot(ctx ExprContext, opTerm *term) (v any, err error) {
var value any
if value, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if IsInteger(value) {
i, _ := value.(int64)
v = ^i
} else {
err = opTerm.errIncompatibleType(value)
}
return
}
//-------- Binary AND term
func newBinAndTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBinAnd,
evalFunc: evalBinaryAnd,
}
}
func evalBinaryAnd(ctx ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
var leftInt, rightInt int64
var lok, rok bool
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt & rightInt
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
}
return
}
//-------- Binary OR term
func newBinOrTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBinOr,
evalFunc: evalBinaryOr,
}
}
func evalBinaryOr(ctx ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
var leftInt, rightInt int64
var lok, rok bool
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt | rightInt
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
}
return
}
// init
func init() {
registerTermConstructor(SymTilde, newBinNotTerm)
registerTermConstructor(SymAmpersand, newBinAndTerm)
registerTermConstructor(SymVertBar, newBinOrTerm)
}
+158
View File
@@ -0,0 +1,158 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-bitwise.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- Bitwise NOT term
func newBitwiseNotTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priBitwiseNot,
evalFunc: evalBitwiseNot,
}
}
func evalBitwiseNot(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var value any
if value, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if kern.IsInteger(value) {
i, _ := value.(int64)
v = ^i
} else {
err = opTerm.errIncompatiblePrefixPostfixType(value)
}
return
}
//-------- Bitwise AND term
func newBitwiseAndTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseAnd,
evalFunc: evalBitwiseAnd,
}
}
func bitwiseAnd(opTerm *term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt & rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseAnd(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitwiseAnd(opTerm, leftValue, rightValue)
return
}
//-------- Bitwise OR term
func newBitwiseOrTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseOr,
evalFunc: evalBitwiseOr,
}
}
func bitwiseOr(opTerm *term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt | rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseOr(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitwiseOr(opTerm, leftValue, rightValue)
return
}
//-------- Bitwise XOR term
func newBitwiseXorTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseOr,
evalFunc: evalBitwiseXor,
}
}
func bitwiseXor(opTerm *term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt ^ rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseXor(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitwiseXor(opTerm, leftValue, rightValue)
return
}
// init
func init() {
registerTermConstructor(SymTilde, newBitwiseNotTerm)
registerTermConstructor(SymAmpersand, newBitwiseAndTerm)
registerTermConstructor(SymVertBar, newBitwiseOrTerm)
registerTermConstructor(SymCaret, newBitwiseXorTerm)
}
+32 -27
View File
@@ -4,7 +4,11 @@
// operator-bool.go
package expr
import "fmt"
import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- NOT term
@@ -18,17 +22,17 @@ func newNotTerm(tk *Token) (inst *term) {
}
}
func evalNot(ctx ExprContext, opTerm *term) (v any, err error) {
func evalNot(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var rightValue any
if rightValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if b, ok := ToBool(rightValue); ok {
if b, ok := kern.ToBool(rightValue); ok {
v = !b
} else {
err = opTerm.errIncompatibleType(rightValue)
err = opTerm.errIncompatiblePrefixPostfixType(rightValue)
}
return
}
@@ -45,8 +49,8 @@ func newAndTerm(tk *Token) (inst *term) {
}
}
func evalAnd(ctx ExprContext, self *term) (v any, err error) {
if CtrlIsEnabled(ctx, ControlBoolShortcut) {
func evalAnd(ctx kern.ExprContext, self *term) (v any, err error) {
if kern.CtrlIsEnabled(ctx, kern.ControlBoolShortcut) {
v, err = evalAndWithShortcut(ctx, self)
} else {
v, err = evalAndWithoutShortcut(ctx, self)
@@ -54,7 +58,7 @@ func evalAnd(ctx ExprContext, self *term) (v any, err error) {
return
}
func evalAndWithoutShortcut(ctx ExprContext, self *term) (v any, err error) {
func evalAndWithoutShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
var leftBool, rightBool bool
var lok, rok bool
@@ -63,8 +67,8 @@ func evalAndWithoutShortcut(ctx ExprContext, self *term) (v any, err error) {
return
}
leftBool, lok = ToBool(leftValue)
rightBool, rok = ToBool(rightValue)
leftBool, lok = kern.ToBool(leftValue)
rightBool, rok = kern.ToBool(rightValue)
if lok && rok {
v = leftBool && rightBool
@@ -74,24 +78,25 @@ func evalAndWithoutShortcut(ctx ExprContext, self *term) (v any, err error) {
return
}
func evalAndWithShortcut(ctx ExprContext, self *term) (v any, err error) {
func evalAndWithShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
if err = self.checkOperands(); err != nil {
return
}
if leftValue, err = self.children[0].compute(ctx); err != nil {
if leftValue, err = self.children[0].Compute(ctx); err != nil {
return
}
if leftBool, lok := ToBool(leftValue); !lok {
err = fmt.Errorf("got %s as left operand type of 'AND' operator, it must be bool", TypeName(leftValue))
return
if leftBool, lok := kern.ToBool(leftValue); !lok {
// err = fmt.Errorf("got %s as left operand type of 'AND' operator, it must be bool", expr.TypeName(leftValue))
// return
err = self.errIncompatibleType(leftValue, "left")
} else if !leftBool {
v = false
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
if rightBool, rok := ToBool(rightValue); rok {
} else if rightValue, err = self.children[1].Compute(ctx); err == nil {
if rightBool, rok := kern.ToBool(rightValue); rok {
v = rightBool
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
@@ -112,8 +117,8 @@ func newOrTerm(tk *Token) (inst *term) {
}
}
func evalOr(ctx ExprContext, self *term) (v any, err error) {
if CtrlIsEnabled(ctx, ControlBoolShortcut) {
func evalOr(ctx kern.ExprContext, self *term) (v any, err error) {
if kern.CtrlIsEnabled(ctx, kern.ControlBoolShortcut) {
v, err = evalOrWithShortcut(ctx, self)
} else {
v, err = evalOrWithoutShortcut(ctx, self)
@@ -121,7 +126,7 @@ func evalOr(ctx ExprContext, self *term) (v any, err error) {
return
}
func evalOrWithoutShortcut(ctx ExprContext, self *term) (v any, err error) {
func evalOrWithoutShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
var leftBool, rightBool bool
var lok, rok bool
@@ -130,8 +135,8 @@ func evalOrWithoutShortcut(ctx ExprContext, self *term) (v any, err error) {
return
}
leftBool, lok = ToBool(leftValue)
rightBool, rok = ToBool(rightValue)
leftBool, lok = kern.ToBool(leftValue)
rightBool, rok = kern.ToBool(rightValue)
if lok && rok {
v = leftBool || rightBool
@@ -141,24 +146,24 @@ func evalOrWithoutShortcut(ctx ExprContext, self *term) (v any, err error) {
return
}
func evalOrWithShortcut(ctx ExprContext, self *term) (v any, err error) {
func evalOrWithShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
if err = self.checkOperands(); err != nil {
return
}
if leftValue, err = self.children[0].compute(ctx); err != nil {
if leftValue, err = self.children[0].Compute(ctx); err != nil {
return
}
if leftBool, lok := ToBool(leftValue); !lok {
err = fmt.Errorf("got %s as left operand type of 'OR' operator, it must be bool", TypeName(leftValue))
if leftBool, lok := kern.ToBool(leftValue); !lok {
err = fmt.Errorf("got %s as left operand type of 'OR' operator, it must be bool", kern.TypeName(leftValue))
return
} else if leftBool {
v = true
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
if rightBool, rok := ToBool(rightValue); rok {
} else if rightValue, err = self.children[1].Compute(ctx); err == nil {
if rightBool, rok := kern.ToBool(rightValue); rok {
v = rightBool
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
+14 -7
View File
@@ -4,7 +4,11 @@
// operator-builtin.go
package expr
import "io"
import (
"io"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- builtin term
@@ -18,7 +22,7 @@ func newBuiltinTerm(tk *Token) (inst *term) {
}
}
func evalBuiltin(ctx ExprContext, opTerm *term) (v any, err error) {
func evalBuiltin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
@@ -26,22 +30,25 @@ func evalBuiltin(ctx ExprContext, opTerm *term) (v any, err error) {
}
count := 0
if IsString(childValue) {
if kern.IsString(childValue) {
module, _ := childValue.(string)
count, err = ImportInContextByGlobPattern(module)
count, err = ImportInContextByGlobPattern(ctx, module)
} else {
var moduleSpec any
it := NewAnyIterator(childValue)
var it kern.Iterator
if it, err = NewIterator(childValue); err != nil {
return
}
for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() {
if module, ok := moduleSpec.(string); ok {
if ImportInContext(module) {
if ImportInContext(ctx, module) {
count++
} else {
err = opTerm.Errorf("unknown builtin module %q", module)
break
}
} else {
err = opTerm.Errorf("expected string at item nr %d, got %s", it.Index()+1, TypeName(moduleSpec))
err = opTerm.Errorf("expected string at item nr %d, got %s", it.Index()+1, kern.TypeName(moduleSpec))
break
}
}
+5 -1
View File
@@ -4,6 +4,10 @@
// operator-but.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- but term
func newButTerm(tk *Token) (inst *term) {
@@ -16,7 +20,7 @@ func newButTerm(tk *Token) (inst *term) {
}
}
func evalBut(ctx ExprContext, opTerm *term) (v any, err error) {
func evalBut(ctx kern.ExprContext, opTerm *term) (v any, err error) {
_, v, err = opTerm.evalInfix(ctx)
return
}
+11 -7
View File
@@ -4,6 +4,10 @@
// operator-context-value.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- context term
func newContextTerm(tk *Token) (inst *term) {
@@ -16,14 +20,14 @@ func newContextTerm(tk *Token) (inst *term) {
}
}
func evalContextValue(ctx ExprContext, opTerm *term) (v any, err error) {
func evalContextValue(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
var sourceCtx ExprContext
var sourceCtx kern.ExprContext
if len(opTerm.children) == 0 {
sourceCtx = ctx
} else if opTerm.children[0].symbol() == SymVariable && opTerm.children[0].source() == "global" {
sourceCtx = globalCtx
} else if opTerm.children[0].symbol() == SymVariable && opTerm.children[0].Source() == "global" {
sourceCtx = ctx.GetGlobal()
} else if childValue, err = opTerm.evalPrefix(ctx); err == nil {
if dc, ok := childValue.(*dataCursor); ok {
sourceCtx = dc.ctx
@@ -31,9 +35,9 @@ func evalContextValue(ctx ExprContext, opTerm *term) (v any, err error) {
}
if sourceCtx != nil {
if formatter, ok := sourceCtx.(DictFormat); ok {
if formatter, ok := sourceCtx.(kern.DictFormat); ok {
v = formatter.ToDict()
} else if formatter, ok := sourceCtx.(Formatter); ok {
} else if formatter, ok := sourceCtx.(kern.Formatter); ok {
v = formatter.ToString(0)
} else {
// keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
@@ -49,7 +53,7 @@ func evalContextValue(ctx ExprContext, opTerm *term) (v any, err error) {
v = d
}
} else {
err = opTerm.errIncompatibleType(childValue)
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
}
return
}
+6 -2
View File
@@ -4,6 +4,10 @@
// operator-ctrl.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- export all term
func newExportAllTerm(tk *Token) (inst *term) {
@@ -16,8 +20,8 @@ func newExportAllTerm(tk *Token) (inst *term) {
}
}
func evalExportAll(ctx ExprContext, opTerm *term) (v any, err error) {
CtrlEnable(ctx, control_export_all)
func evalExportAll(ctx kern.ExprContext, opTerm *term) (v any, err error) {
CtrlEnable(ctx, kern.ControlExportAll)
return
}
+20 -16
View File
@@ -4,6 +4,10 @@
// operator-default.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- default term
func newDefaultTerm(tk *Token) (inst *term) {
@@ -16,7 +20,7 @@ func newDefaultTerm(tk *Token) (inst *term) {
}
}
func evalDefault(ctx ExprContext, opTerm *term) (v any, err error) {
func evalDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var rightValue any
if err = opTerm.checkOperands(); err != nil {
@@ -26,13 +30,13 @@ func evalDefault(ctx ExprContext, opTerm *term) (v any, err error) {
leftTerm := opTerm.children[0]
if leftTerm.tk.Sym != SymVariable {
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
err = ErrLeftOperandMustBeVariable(leftTerm, opTerm)
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
return
}
if leftValue, exists := ctx.GetVar(leftTerm.source()); exists {
if leftValue, exists := ctx.GetVar(leftTerm.Source()); exists {
v = leftValue
} else if rightValue, err = opTerm.children[1].compute(ctx); err == nil {
} else if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
v = rightValue
}
return
@@ -50,7 +54,7 @@ func newAlternateTerm(tk *Token) (inst *term) {
}
}
func evalAlternate(ctx ExprContext, opTerm *term) (v any, err error) {
func evalAlternate(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var rightValue any
if err = opTerm.checkOperands(); err != nil {
@@ -60,12 +64,12 @@ func evalAlternate(ctx ExprContext, opTerm *term) (v any, err error) {
leftTerm := opTerm.children[0]
if leftTerm.tk.Sym != SymVariable {
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
err = ErrLeftOperandMustBeVariable(leftTerm, opTerm)
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
return
}
if leftValue, exists := ctx.GetVar(leftTerm.source()); exists && leftValue != nil {
if rightValue, err = opTerm.children[1].compute(ctx); err == nil {
if leftValue, exists := ctx.GetVar(leftTerm.Source()); exists && leftValue != nil {
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
v = rightValue
}
} else {
@@ -86,7 +90,7 @@ func newDefaultAssignTerm(tk *Token) (inst *term) {
}
}
func evalAssignDefault(ctx ExprContext, opTerm *term) (v any, err error) {
func evalAssignDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var rightValue any
if err = opTerm.checkOperands(); err != nil {
@@ -96,21 +100,21 @@ func evalAssignDefault(ctx ExprContext, opTerm *term) (v any, err error) {
leftTerm := opTerm.children[0]
if leftTerm.tk.Sym != SymVariable {
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
err = ErrLeftOperandMustBeVariable(leftTerm, opTerm)
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
return
}
if leftValue, exists := ctx.GetVar(leftTerm.source()); exists {
if leftValue, exists := ctx.GetVar(leftTerm.Source()); exists {
v = leftValue
} else if rightValue, err = opTerm.children[1].compute(ctx); err == nil {
if functor, ok := rightValue.(Functor); ok {
} else if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
if functor, ok := rightValue.(kern.Functor); ok {
//ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
ctx.RegisterFunc(leftTerm.source(), functor, TypeAny, []ExprFuncParam{
NewFuncParamFlag(ParamValue, PfDefault|PfRepeat),
ctx.RegisterFunc(leftTerm.Source(), functor, kern.TypeAny, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamValue, PfDefault|PfRepeat),
})
} else {
v = rightValue
ctx.UnsafeSetVar(leftTerm.source(), rightValue)
ctx.UnsafeSetVar(leftTerm.Source(), rightValue)
}
}
return
+72
View File
@@ -0,0 +1,72 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-digest.go
package expr
import (
"fmt"
"io"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- digest term
func newDigestTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priIterOp,
evalFunc: evalDigest,
}
}
func evalDigest(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
var it kern.Iterator
var item, lastValue any
if err = opTerm.checkOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
return
}
if it, err = NewIterator(leftValue); err != nil {
return nil, fmt.Errorf("left operand of DIGEST must be an iterable data-source; got %s", kern.TypeName(leftValue))
}
lastValue = nil
for item, err = it.Next(); err == nil; item, err = it.Next() {
ctx.SetVar("_", item)
ctx.SetVar("_index", it.Index())
ctx.SetVar("_count", it.Count())
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
if rightValue == nil {
break
} else {
lastValue = rightValue
}
}
ctx.DeleteVar("_count")
ctx.DeleteVar("_index")
ctx.DeleteVar("_")
if err != nil {
break
}
}
if err == io.EOF {
err = nil
}
v = lastValue
return
}
// init
func init() {
registerTermConstructor(SymKwDigest, newDigestTerm)
}
+9 -5
View File
@@ -4,6 +4,10 @@
// operator-dot.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- dot term
func newDotTerm(tk *Token) (inst *term) {
return &term{
@@ -15,22 +19,22 @@ func newDotTerm(tk *Token) (inst *term) {
}
}
func evalDot(ctx ExprContext, opTerm *term) (v any, err error) {
func evalDot(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if err = opTerm.checkOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].compute(ctx); err != nil {
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
return
}
indexTerm := opTerm.children[1]
switch unboxedValue := leftValue.(type) {
case ExtIterator:
case kern.ExtIterator:
if indexTerm.symbol() == SymVariable /*|| indexTerm.symbol() == SymString */ {
opName := indexTerm.source()
opName := indexTerm.Source()
if unboxedValue.HasOperation(opName) {
v, err = unboxedValue.CallOperation(opName, map[string]any{})
} else {
@@ -41,7 +45,7 @@ func evalDot(ctx ExprContext, opTerm *term) (v any, err error) {
err = indexTerm.tk.ErrorExpectedGot("identifier")
}
default:
if rightValue, err = opTerm.children[1].compute(ctx); err == nil {
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
}
+8 -4
View File
@@ -4,7 +4,11 @@
// operator-fact.go
package expr
import "fmt"
import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- fact term
@@ -18,14 +22,14 @@ func newFactTerm(tk *Token) (inst *term) {
}
}
func evalFact(ctx ExprContext, opTerm *term) (v any, err error) {
func evalFact(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue any
if leftValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if IsInteger(leftValue) {
if kern.IsInteger(leftValue) {
if i, _ := leftValue.(int64); i >= 0 {
f := int64(1)
for k := int64(1); k <= i; k++ {
@@ -36,7 +40,7 @@ func evalFact(ctx ExprContext, opTerm *term) (v any, err error) {
err = fmt.Errorf("factorial of a negative integer (%d) is not allowed", i)
}
} else {
err = opTerm.errIncompatibleType(leftValue)
err = opTerm.errIncompatiblePrefixPostfixType(leftValue)
}
return
}
+74
View File
@@ -0,0 +1,74 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-filter.go
package expr
import (
"fmt"
"io"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- map term
func newFilterTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priIterOp,
evalFunc: evalFilter,
}
}
func evalFilter(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
var it kern.Iterator
var item any
if err = opTerm.checkOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
return
}
if it, err = NewIterator(leftValue); err != nil {
return nil, fmt.Errorf("left operand of FILTER must be an iterable data-source; got %s", kern.TypeName(leftValue))
}
values := kern.NewListA()
for item, err = it.Next(); err == nil; item, err = it.Next() {
ctx.SetVar("_", item)
ctx.SetVar("_index", it.Index())
ctx.SetVar("_count", it.Count())
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
if success, valid := kern.ToBool(rightValue); valid {
if success {
values.AppendItem(item)
}
} else {
err = fmt.Errorf("filter expression must return a boolean or a castable to boolean, got %v [%T]", rightValue, rightValue)
}
}
ctx.DeleteVar("_count")
ctx.DeleteVar("_index")
ctx.DeleteVar("_")
if err != nil {
break
}
}
if err == io.EOF {
err = nil
}
v = values
return
}
// init
func init() {
registerTermConstructor(SymKwFilter, newFilterTerm)
}
+9 -4
View File
@@ -8,6 +8,8 @@ package expr
import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- fraction term
@@ -23,7 +25,7 @@ func newFractionTerm(tk *Token) *term {
}
// -------- eval func
func evalFraction(ctx ExprContext, opTerm *term) (v any, err error) {
func evalFraction(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var numValue, denValue any
var num, den int64
var ok bool
@@ -49,16 +51,19 @@ func evalFraction(ctx ExprContext, opTerm *term) (v any, err error) {
num = -num
}
if num != 0 {
g := gcd(num, den)
if g := kern.Gcd(num, den); g != 1 {
num = num / g
den = den / g
}
if den == 1 {
v = num
} else {
v = &FractionType{num, den}
// v = &expr.FractionType{num, den}
v = kern.NewFraction(num, den)
}
} else {
v = &FractionType{0, den}
// v = &FractionType{0, den}
v = kern.NewFraction(0, den)
}
return
}
+11 -7
View File
@@ -4,6 +4,10 @@
// operator-in.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- in term
func newInTerm(tk *Token) (inst *term) {
@@ -21,19 +25,19 @@ func newInTerm(tk *Token) (inst *term) {
// return
// }
func evalIn(ctx ExprContext, opTerm *term) (v any, err error) {
func evalIn(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
if IsList(rightValue) {
list, _ := rightValue.(*ListType)
v = list.indexDeepSameCmp(leftValue) >= 0
} else if IsDict(rightValue) {
dict, _ := rightValue.(*DictType)
v = dict.hasKey(leftValue)
if kern.IsList(rightValue) {
list, _ := rightValue.(*kern.ListType)
v = list.IndexDeepSameCmp(leftValue) >= 0
} else if kern.IsDict(rightValue) {
dict, _ := rightValue.(*kern.DictType)
v = dict.HasKey(leftValue)
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
+9 -5
View File
@@ -4,6 +4,10 @@
// operator-include.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- include term
func newIncludeTerm(tk *Token) (inst *term) {
@@ -16,7 +20,7 @@ func newIncludeTerm(tk *Token) (inst *term) {
}
}
func evalInclude(ctx ExprContext, opTerm *term) (v any, err error) {
func evalInclude(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
@@ -24,8 +28,8 @@ func evalInclude(ctx ExprContext, opTerm *term) (v any, err error) {
}
count := 0
if IsList(childValue) {
list, _ := childValue.(*ListType)
if kern.IsList(childValue) {
list, _ := childValue.(*kern.ListType)
for i, filePathSpec := range *list {
if filePath, ok := filePathSpec.(string); ok {
if v, err = EvalFile(ctx, filePath); err == nil {
@@ -39,13 +43,13 @@ func evalInclude(ctx ExprContext, opTerm *term) (v any, err error) {
break
}
}
} else if IsString(childValue) {
} else if kern.IsString(childValue) {
filePath, _ := childValue.(string)
if v, err = EvalFile(ctx, filePath); err == nil {
count++
}
} else {
err = opTerm.errIncompatibleType(childValue)
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
}
if err != nil {
//v = count
+20 -16
View File
@@ -4,6 +4,10 @@
// operator-index.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- index term
func newIndexTerm(tk *Token) (inst *term) {
return &term{
@@ -15,15 +19,15 @@ func newIndexTerm(tk *Token) (inst *term) {
}
}
func verifyKey(indexList *ListType) (index any, err error) {
func verifyKey(indexList *kern.ListType) (index any, err error) {
index = (*indexList)[0]
return
}
func verifyIndex(indexTerm *term, indexList *ListType, maxValue int) (index int, err error) {
func verifyIndex(indexTerm *term, indexList *kern.ListType, maxValue int) (index int, err error) {
var v int
if v, err = ToGoInt((*indexList)[0], "index expression"); err == nil {
if v, err = kern.ToGoInt((*indexList)[0], "index expression"); err == nil {
if v < 0 && v >= -maxValue {
v = maxValue + v
}
@@ -36,11 +40,11 @@ func verifyIndex(indexTerm *term, indexList *ListType, maxValue int) (index int,
return
}
func verifyRange(indexTerm *term, indexList *ListType, maxValue int) (startIndex, endIndex int, err error) {
func verifyRange(indexTerm *term, indexList *kern.ListType, maxValue int) (startIndex, endIndex int, err error) {
v, _ := ((*indexList)[0]).(*intPair)
startIndex = v.a
endIndex = v.b
if endIndex == ConstLastIndex {
if endIndex == kern.ConstLastIndex {
endIndex = maxValue
}
if startIndex < 0 && startIndex >= -maxValue {
@@ -59,9 +63,9 @@ func verifyRange(indexTerm *term, indexList *ListType, maxValue int) (startIndex
return
}
func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) {
func evalIndex(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
var indexList *ListType
var indexList *kern.ListType
var ok bool
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
@@ -69,7 +73,7 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) {
}
indexTerm := opTerm.children[1]
if indexList, ok = rightValue.(*ListType); !ok {
if indexList, ok = rightValue.(*kern.ListType); !ok {
err = opTerm.Errorf("invalid index expression")
return
} else if len(*indexList) != 1 {
@@ -77,9 +81,9 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) {
return
}
if IsInteger((*indexList)[0]) {
if kern.IsInteger((*indexList)[0]) {
switch unboxedValue := leftValue.(type) {
case *ListType:
case *kern.ListType:
var index int
if index, err = verifyIndex(indexTerm, indexList, len(*unboxedValue)); err == nil {
v = (*unboxedValue)[index]
@@ -89,17 +93,17 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) {
if index, err = verifyIndex(indexTerm, indexList, len(unboxedValue)); err == nil {
v = string(unboxedValue[index])
}
case *DictType:
case *kern.DictType:
v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue)
default:
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
} else if isIntPair((*indexList)[0]) {
switch unboxedValue := leftValue.(type) {
case *ListType:
case *kern.ListType:
var start, end int
if start, end, err = verifyRange(indexTerm, indexList, len(*unboxedValue)); err == nil {
sublist := ListType((*unboxedValue)[start:end])
sublist := kern.ListType((*unboxedValue)[start:end])
v = &sublist
}
case string:
@@ -110,8 +114,8 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) {
default:
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
} else if IsDict(leftValue) {
d := leftValue.(*DictType)
} else if kern.IsDict(leftValue) {
d := leftValue.(*kern.DictType)
v, err = getDictItem(d, indexTerm, indexList, rightValue)
} else {
rightChild := opTerm.children[1]
@@ -120,7 +124,7 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) {
return
}
func getDictItem(d *DictType, indexTerm *term, indexList *ListType, rightValue any) (v any, err error) {
func getDictItem(d *kern.DictType, indexTerm *term, indexList *kern.ListType, rightValue any) (v any, err error) {
var ok bool
var indexValue any
+13 -9
View File
@@ -4,6 +4,10 @@
// operator-insert.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- prepend term
func newPrependTerm(tk *Token) (inst *term) {
@@ -26,19 +30,19 @@ func newAppendTerm(tk *Token) (inst *term) {
}
}
func evalPrepend(ctx ExprContext, opTerm *term) (v any, err error) {
func evalPrepend(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
if IsList(rightValue) {
list, _ := rightValue.(*ListType)
newList := append(ListType{leftValue}, *list...)
if kern.IsList(rightValue) {
list, _ := rightValue.(*kern.ListType)
newList := append(kern.ListType{leftValue}, *list...)
v = &newList
if opTerm.children[1].symbol() == SymVariable {
ctx.UnsafeSetVar(opTerm.children[1].source(), v)
ctx.UnsafeSetVar(opTerm.children[1].Source(), v)
}
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
@@ -46,19 +50,19 @@ func evalPrepend(ctx ExprContext, opTerm *term) (v any, err error) {
return
}
func evalAppend(ctx ExprContext, opTerm *term) (v any, err error) {
func evalAppend(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
if IsList(leftValue) {
list, _ := leftValue.(*ListType)
if kern.IsList(leftValue) {
list, _ := leftValue.(*kern.ListType)
newList := append(*list, rightValue)
v = &newList
if opTerm.children[0].symbol() == SymVariable {
ctx.UnsafeSetVar(opTerm.children[0].source(), v)
ctx.UnsafeSetVar(opTerm.children[0].Source(), v)
}
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
+9 -5
View File
@@ -4,6 +4,10 @@
// operator-iter-value.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- iter value term
func newIterValueTerm(tk *Token) (inst *term) {
@@ -11,22 +15,22 @@ func newIterValueTerm(tk *Token) (inst *term) {
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priIterValue,
priority: priDereference,
evalFunc: evalIterValue,
}
}
func evalIterValue(ctx ExprContext, opTerm *term) (v any, err error) {
func evalIterValue(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if it, ok := childValue.(Iterator); ok {
if it, ok := childValue.(kern.Iterator); ok {
v, err = it.Current()
} else {
err = opTerm.errIncompatibleType(childValue)
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
}
return
}
@@ -34,5 +38,5 @@ func evalIterValue(ctx ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
// registerTermConstructor(SymOpenClosedRound, newIterValueTerm)
registerTermConstructor(SymCaret, newIterValueTerm)
registerTermConstructor(SymDereference, newIterValueTerm)
}
+67
View File
@@ -0,0 +1,67 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-join.go
package expr
import (
"fmt"
"io"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- join term
func newJoinTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priIterOp,
evalFunc: evalJoin,
}
}
func evalJoin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
var itLeft, itRight kern.Iterator
var item any
if err = opTerm.checkOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
return
}
if rightValue, err = opTerm.children[1].Compute(ctx); err != nil {
return
}
if itLeft, err = NewIterator(leftValue); err != nil {
return nil, fmt.Errorf("left operand of JOIN must be an iterable data-source; got %s", kern.TypeName(leftValue))
}
if itRight, err = NewIterator(rightValue); err != nil {
return nil, fmt.Errorf("right operand of JOIN must be an iterable data-source; got %s", kern.TypeName(rightValue))
}
values := kern.NewListA()
for _, it := range []kern.Iterator{itLeft, itRight} {
for item, err = it.Next(); err == nil; item, err = it.Next() {
values.AppendItem(item)
}
}
if err == io.EOF {
err = nil
}
v = values
return
}
// init
func init() {
registerTermConstructor(SymKwJoin, newJoinTerm)
}
+12 -8
View File
@@ -4,6 +4,10 @@
// operator-length.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- length term
func newLengthTerm(tk *Token) (inst *term) {
@@ -16,23 +20,23 @@ func newLengthTerm(tk *Token) (inst *term) {
}
}
func evalLength(ctx ExprContext, opTerm *term) (v any, err error) {
func evalLength(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if IsList(childValue) {
ls, _ := childValue.(*ListType)
if kern.IsList(childValue) {
ls, _ := childValue.(*kern.ListType)
v = int64(len(*ls))
} else if IsString(childValue) {
} else if kern.IsString(childValue) {
s, _ := childValue.(string)
v = int64(len(s))
} else if IsDict(childValue) {
m, _ := childValue.(*DictType)
} else if kern.IsDict(childValue) {
m, _ := childValue.(*kern.DictType)
v = int64(len(*m))
} else if it, ok := childValue.(Iterator); ok {
} else if it, ok := childValue.(kern.Iterator); ok {
v = int64(it.Count())
// if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(CountName) {
// count, _ := extIt.CallOperation(CountName, nil)
@@ -41,7 +45,7 @@ func evalLength(ctx ExprContext, opTerm *term) (v any, err error) {
// v = int64(it.Index() + 1)
// }
} else {
err = opTerm.errIncompatibleType(childValue)
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
}
return
}
+68
View File
@@ -0,0 +1,68 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-map.go
package expr
import (
"fmt"
"io"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- map term
func newMapTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priIterOp,
evalFunc: evalMap,
}
}
func evalMap(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
var it kern.Iterator
var item any
if err = opTerm.checkOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
return
}
if it, err = NewIterator(leftValue); err != nil {
return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue))
}
values := kern.NewListA()
for item, err = it.Next(); err == nil; item, err = it.Next() {
ctx.SetVar("_", item)
ctx.SetVar("_index", it.Index())
ctx.SetVar("_count", it.Count())
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
values.AppendItem(rightValue)
}
ctx.DeleteVar("_count")
ctx.DeleteVar("_index")
ctx.DeleteVar("_")
if err != nil {
break
}
}
if err == io.EOF {
err = nil
}
v = values
return
}
// init
func init() {
registerTermConstructor(SymKwMap, newMapTerm)
}
+6 -2
View File
@@ -4,6 +4,10 @@
// operator-plugin.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- plugin term
func newPluginTerm(tk *Token) (inst *term) {
@@ -16,7 +20,7 @@ func newPluginTerm(tk *Token) (inst *term) {
}
}
func evalPlugin(ctx ExprContext, opTerm *term) (v any, err error) {
func evalPlugin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
var count int
@@ -24,7 +28,7 @@ func evalPlugin(ctx ExprContext, opTerm *term) (v any, err error) {
return
}
if count, err = importPluginFromSearchPath(childValue); err == nil {
if count, err = importPluginFromSearchPath(ctx, childValue); err == nil {
v = int64(count)
}
return
+97
View File
@@ -0,0 +1,97 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-post-inc-dec.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- post increment term
func newPostIncTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPostfix,
priority: priIncDec,
evalFunc: evalPostInc,
}
}
func evalPostInc(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if it, ok := childValue.(kern.Iterator); ok {
var namePrefix string
v, err = it.Next()
if opTerm.children[0].symbol() == SymVariable {
namePrefix = opTerm.children[0].Source()
}
ctx.UnsafeSetVar(namePrefix+"_index", it.Index())
if c, err1 := it.Current(); err1 == nil {
ctx.UnsafeSetVar(namePrefix+"_current", c)
}
if it.HasOperation(kern.KeyName) {
if k, err1 := it.CallOperation(kern.KeyName, nil); err1 == nil {
ctx.UnsafeSetVar(namePrefix+"_key", k)
}
}
if it.HasOperation(kern.ValueName) {
if v1, err1 := it.CallOperation(kern.ValueName, nil); err1 == nil {
ctx.UnsafeSetVar(namePrefix+"_value", v1)
}
}
} else if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
v = childValue
i, _ := childValue.(int64)
ctx.SetVar(opTerm.children[0].Source(), i+1)
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
}
return
}
// -------- post decrement term
func newPostDecTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPostfix,
priority: priIncDec,
evalFunc: evalPostDec,
}
}
func evalPostDec(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
/* if it, ok := childValue.(Iterator); ok {
v, err = it.Next()
} else */if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
v = childValue
i, _ := childValue.(int64)
ctx.SetVar(opTerm.children[0].Source(), i-1)
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
}
return
}
// init
func init() {
registerTermConstructor(SymDoublePlus, newPostIncTerm)
registerTermConstructor(SymDoubleMinus, newPostDecTerm)
}
-73
View File
@@ -1,73 +0,0 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-post-inc.go
package expr
// -------- post increment term
func newPostIncTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPostfix,
priority: priIncDec,
evalFunc: evalPostInc,
}
}
func evalPostInc(ctx ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if it, ok := childValue.(Iterator); ok {
v, err = it.Next()
} else if IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
v = childValue
i, _ := childValue.(int64)
ctx.SetVar(opTerm.children[0].source(), i+1)
} else {
err = opTerm.errIncompatibleType(childValue)
}
return
}
// -------- post decrement term
func newPostDecTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPostfix,
priority: priIncDec,
evalFunc: evalPostDec,
}
}
func evalPostDec(ctx ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
/* if it, ok := childValue.(Iterator); ok {
v, err = it.Next()
} else */if IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
v = childValue
i, _ := childValue.(int64)
ctx.SetVar(opTerm.children[0].source(), i-1)
} else {
err = opTerm.errIncompatibleType(childValue)
}
return
}
// init
func init() {
registerTermConstructor(SymDoublePlus, newPostIncTerm)
registerTermConstructor(SymDoubleMinus, newPostDecTerm)
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-pre-inc-dec.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- pre increment term
func newPreIncTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priIncDec,
evalFunc: evalPreInc,
}
}
func evalPreInc(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
i := childValue.(int64) + 1
ctx.SetVar(opTerm.children[0].Source(), i)
v = i
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
}
return
}
// -------- pre decrement term
func newPreDecTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priIncDec,
evalFunc: evalPreDec,
}
}
func evalPreDec(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
i := childValue.(int64) - 1
ctx.SetVar(opTerm.children[0].Source(), i)
v = i
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
}
return
}
// init
func init() {
registerTermConstructor(SymPreInc, newPreIncTerm)
registerTermConstructor(SymPreDec, newPreDecTerm)
}
+26 -24
View File
@@ -6,6 +6,8 @@ package expr
import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- multiply term
@@ -21,15 +23,15 @@ func newMultiplyTerm(tk *Token) (inst *term) {
}
func mulValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
if IsString(leftValue) && IsInteger(rightValue) {
if kern.IsString(leftValue) && kern.IsInteger(rightValue) {
s, _ := leftValue.(string)
n, _ := rightValue.(int64)
v = strings.Repeat(s, int(n))
} else if isNumOrFract(leftValue) && isNumOrFract(rightValue) {
if IsFloat(leftValue) || IsFloat(rightValue) {
v = numAsFloat(leftValue) * numAsFloat(rightValue)
} else if isFraction(leftValue) || isFraction(rightValue) {
v, err = mulAnyFract(leftValue, rightValue)
} else if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
v = kern.NumAsFloat(leftValue) * kern.NumAsFloat(rightValue)
} else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) {
v, err = kern.MulAnyFract(leftValue, rightValue)
} else {
leftInt, _ := leftValue.(int64)
rightInt, _ := rightValue.(int64)
@@ -41,7 +43,7 @@ func mulValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
return
}
func evalMultiply(ctx ExprContext, prodTerm *term) (v any, err error) {
func evalMultiply(ctx kern.ExprContext, prodTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = prodTerm.evalInfix(ctx); err != nil {
@@ -64,16 +66,16 @@ func newDivideTerm(tk *Token) (inst *term) {
}
func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
if isNumOrFract(leftValue) && isNumOrFract(rightValue) {
if IsFloat(leftValue) || IsFloat(rightValue) {
d := numAsFloat(rightValue)
if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
d := kern.NumAsFloat(rightValue)
if d == 0.0 {
err = opTerm.errDivisionByZero()
} else {
v = numAsFloat(leftValue) / d
v = kern.NumAsFloat(leftValue) / d
}
} else if isFraction(leftValue) || isFraction(rightValue) {
v, err = divAnyFract(leftValue, rightValue)
} else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) {
v, err = kern.DivAnyFract(leftValue, rightValue)
} else {
leftInt, _ := leftValue.(int64)
if rightInt, _ := rightValue.(int64); rightInt == 0 {
@@ -82,11 +84,11 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
v = leftInt / rightInt
}
}
} else if IsString(leftValue) && IsString(rightValue) {
} else if kern.IsString(leftValue) && kern.IsString(rightValue) {
source := leftValue.(string)
sep := rightValue.(string)
v = ListFromStrings(strings.Split(source, sep))
} else if IsString(leftValue) && IsInteger(rightValue) {
v = kern.ListFromStrings(strings.Split(source, sep))
} else if kern.IsString(leftValue) && kern.IsInteger(rightValue) {
source := leftValue.(string)
partSize := int(rightValue.(int64))
if partSize == 0 {
@@ -105,7 +107,7 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
if remainder > 0 {
parts = append(parts, source[len(source)-remainder:])
}
v = newList(parts)
v = kern.NewList(parts)
}
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
@@ -113,7 +115,7 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
return
}
func evalDivide(ctx ExprContext, opTerm *term) (v any, err error) {
func evalDivide(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
@@ -135,19 +137,19 @@ func newDivideAsFloatTerm(tk *Token) (inst *term) {
}
}
func evalDivideAsFloat(ctx ExprContext, floatDivTerm *term) (v any, err error) {
func evalDivideAsFloat(ctx kern.ExprContext, floatDivTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = floatDivTerm.evalInfix(ctx); err != nil {
return
}
if isNumOrFract(leftValue) && isNumOrFract(rightValue) {
d := numAsFloat(rightValue)
if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
d := kern.NumAsFloat(rightValue)
if d == 0.0 {
err = floatDivTerm.errDivisionByZero()
} else {
v = numAsFloat(leftValue) / d
v = kern.NumAsFloat(leftValue) / d
}
} else {
err = floatDivTerm.errIncompatibleTypes(leftValue, rightValue)
@@ -167,7 +169,7 @@ func newRemainderTerm(tk *Token) (inst *term) {
}
}
func remainderValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
if IsInteger(leftValue) && IsInteger(rightValue) {
if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) {
rightInt, _ := rightValue.(int64)
if rightInt == 0 {
err = opTerm.errDivisionByZero()
@@ -181,7 +183,7 @@ func remainderValues(opTerm *term, leftValue, rightValue any) (v any, err error)
return
}
func evalRemainder(ctx ExprContext, remainderTerm *term) (v any, err error) {
func evalRemainder(ctx kern.ExprContext, remainderTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = remainderTerm.evalInfix(ctx); err != nil {
+11 -7
View File
@@ -4,7 +4,11 @@
// operator-range.go
package expr
import "fmt"
import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
)
// -------- range term
type intPair struct {
@@ -12,10 +16,10 @@ type intPair struct {
}
func (p *intPair) TypeName() string {
return TypePair
return kern.TypePair
}
func (p *intPair) ToString(opt FmtOpt) string {
func (p *intPair) ToString(opt kern.FmtOpt) string {
return fmt.Sprintf("(%d, %d)", p.a, p.b)
}
@@ -41,21 +45,21 @@ func changeColonToRange(t *term) {
}
}
func evalRange(ctx ExprContext, opTerm *term) (v any, err error) {
func evalRange(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if len(opTerm.children) == 0 {
leftValue = int64(0)
rightValue = int64(-1)
} else if len(opTerm.children) == 1 {
if leftValue, err = opTerm.children[0].compute(ctx); err != nil {
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
return
}
rightValue = int64(ConstLastIndex)
rightValue = int64(kern.ConstLastIndex)
} else if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
if !(IsInteger(leftValue) && IsInteger(rightValue)) {
if !(kern.IsInteger(leftValue) && kern.IsInteger(rightValue)) {
// err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = errRangeInvalidSpecification(opTerm)
return
+32 -28
View File
@@ -4,7 +4,11 @@
// operator-rel.go
package expr
import "reflect"
import (
"reflect"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- equal term
@@ -18,25 +22,25 @@ func newEqualTerm(tk *Token) (inst *term) {
}
}
type deepFuncTemplate func(a, b any) (eq bool, err error)
// type deepFuncTemplate func(a, b any) (eq bool, err error)
func equals(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) {
if isNumOrFract(a) && isNumOrFract(b) {
if IsNumber(a) && IsNumber(b) {
if IsInteger(a) && IsInteger(b) {
func equals(a, b any, deepCmp kern.DeepFuncTemplate) (eq bool, err error) {
if kern.IsNumOrFract(a) && kern.IsNumOrFract(b) {
if kern.IsNumber(a) && kern.IsNumber(b) {
if kern.IsInteger(a) && kern.IsInteger(b) {
li, _ := a.(int64)
ri, _ := b.(int64)
eq = li == ri
} else {
eq = numAsFloat(a) == numAsFloat(b)
eq = kern.NumAsFloat(a) == kern.NumAsFloat(b)
}
} else {
var cmp int
if cmp, err = cmpAnyFract(a, b); err == nil {
if cmp, err = kern.CmpAnyFract(a, b); err == nil {
eq = cmp == 0
}
}
} else if deepCmp != nil && IsList(a) && IsList(b) {
} else if deepCmp != nil && kern.IsList(a) && kern.IsList(b) {
eq, err = deepCmp(a, b)
} else {
eq = reflect.DeepEqual(a, b)
@@ -45,7 +49,7 @@ func equals(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) {
return
}
func evalEqual(ctx ExprContext, opTerm *term) (v any, err error) {
func evalEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
@@ -68,9 +72,9 @@ func newNotEqualTerm(tk *Token) (inst *term) {
}
}
func evalNotEqual(ctx ExprContext, opTerm *term) (v any, err error) {
func evalNotEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
if v, err = evalEqual(ctx, opTerm); err == nil {
b, _ := ToBool(v)
b, _ := kern.ToBool(v)
v = !b
}
return
@@ -89,37 +93,37 @@ func newLessTerm(tk *Token) (inst *term) {
}
func lessThan(self *term, a, b any) (isLess bool, err error) {
if isNumOrFract(a) && isNumOrFract(b) {
if IsNumber(a) && IsNumber(b) {
if IsInteger(a) && IsInteger(b) {
if kern.IsNumOrFract(a) && kern.IsNumOrFract(b) {
if kern.IsNumber(a) && kern.IsNumber(b) {
if kern.IsInteger(a) && kern.IsInteger(b) {
li, _ := a.(int64)
ri, _ := b.(int64)
isLess = li < ri
} else {
isLess = numAsFloat(a) < numAsFloat(b)
isLess = kern.NumAsFloat(a) < kern.NumAsFloat(b)
}
} else {
var cmp int
if cmp, err = cmpAnyFract(a, b); err == nil {
if cmp, err = kern.CmpAnyFract(a, b); err == nil {
isLess = cmp < 0
}
}
} else if IsString(a) && IsString(b) {
} else if kern.IsString(a) && kern.IsString(b) {
ls, _ := a.(string)
rs, _ := b.(string)
isLess = ls < rs
// Inclusion test
} else if IsList(a) && IsList(b) {
aList, _ := a.(*ListType)
bList, _ := b.(*ListType)
isLess = len(*aList) < len(*bList) && bList.contains(aList)
} else if kern.IsList(a) && kern.IsList(b) {
aList, _ := a.(*kern.ListType)
bList, _ := b.(*kern.ListType)
isLess = len(*aList) < len(*bList) && bList.Contains(aList)
} else {
err = self.errIncompatibleTypes(a, b)
}
return
}
func evalLess(ctx ExprContext, opTerm *term) (v any, err error) {
func evalLess(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
@@ -144,8 +148,8 @@ func newLessEqualTerm(tk *Token) (inst *term) {
func lessThanOrEqual(self *term, a, b any) (isLessEq bool, err error) {
if isLessEq, err = lessThan(self, a, b); err == nil {
if !isLessEq {
if IsList(a) && IsList(b) {
isLessEq, err = sameContent(a, b)
if kern.IsList(a) && kern.IsList(b) {
isLessEq, err = kern.SameContent(a, b)
} else {
isLessEq, err = equals(a, b, nil)
}
@@ -154,7 +158,7 @@ func lessThanOrEqual(self *term, a, b any) (isLessEq bool, err error) {
return
}
func evalLessEqual(ctx ExprContext, opTerm *term) (v any, err error) {
func evalLessEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
@@ -178,7 +182,7 @@ func newGreaterTerm(tk *Token) (inst *term) {
}
}
func evalGreater(ctx ExprContext, opTerm *term) (v any, err error) {
func evalGreater(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
@@ -201,7 +205,7 @@ func newGreaterEqualTerm(tk *Token) (inst *term) {
}
}
func evalGreaterEqual(ctx ExprContext, opTerm *term) (v any, err error) {
func evalGreaterEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
+8 -4
View File
@@ -4,6 +4,10 @@
// operator-selector.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- selector term
func newSelectorTerm(tk *Token) (inst *term) {
@@ -16,7 +20,7 @@ func newSelectorTerm(tk *Token) (inst *term) {
}
}
func trySelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (match bool, selectedValue any, err error) {
func trySelectorCase(ctx kern.ExprContext, exprValue, caseSel any, caseIndex int) (match bool, selectedValue any, err error) {
caseData, _ := caseSel.(*selectorCase)
if caseData.filterList == nil {
selectedValue, err = caseData.caseExpr.Eval(ctx)
@@ -38,7 +42,7 @@ func trySelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (ma
} else {
var caseValue any
for _, caseTerm := range filterList {
if caseValue, err = caseTerm.compute(ctx); err != nil || caseValue == exprValue {
if caseValue, err = caseTerm.Compute(ctx); err != nil || caseValue == exprValue {
selectedValue, err = caseData.caseExpr.Eval(ctx)
match = true
break
@@ -49,7 +53,7 @@ func trySelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (ma
return
}
func evalSelector(ctx ExprContext, opTerm *term) (v any, err error) {
func evalSelector(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var exprValue any
var match bool
@@ -57,7 +61,7 @@ func evalSelector(ctx ExprContext, opTerm *term) (v any, err error) {
return
}
exprTerm := opTerm.children[0]
if exprValue, err = exprTerm.compute(ctx); err != nil {
if exprValue, err = exprTerm.Compute(ctx); err != nil {
return
}
+28 -32
View File
@@ -4,7 +4,11 @@
// operator-shift.go
package expr
//-------- shift term
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- bit right shift term
func newRightShiftTerm(tk *Token) (inst *term) {
return &term{
@@ -16,14 +20,8 @@ func newRightShiftTerm(tk *Token) (inst *term) {
}
}
func evalRightShift(ctx ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
if IsInteger(leftValue) && IsInteger(rightValue) {
func bitRightShift(opTerm *term, leftValue, rightValue any) (v any, err error) {
if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) {
leftInt := leftValue.(int64)
rightInt := rightValue.(int64)
v = leftInt >> rightInt
@@ -33,6 +31,17 @@ func evalRightShift(ctx ExprContext, opTerm *term) (v any, err error) {
return
}
func evalRightShift(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitRightShift(opTerm, leftValue, rightValue)
return
}
func newLeftShiftTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
@@ -43,14 +52,8 @@ func newLeftShiftTerm(tk *Token) (inst *term) {
}
}
func evalLeftShift(ctx ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
if IsInteger(leftValue) && IsInteger(rightValue) {
func bitLeftShift(opTerm *term, leftValue, rightValue any) (v any, err error) {
if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) {
leftInt := leftValue.(int64)
rightInt := rightValue.(int64)
v = leftInt << rightInt
@@ -60,23 +63,16 @@ func evalLeftShift(ctx ExprContext, opTerm *term) (v any, err error) {
return
}
// func evalAssignAppend(ctx ExprContext, self *term) (v any, err error) {
// var leftValue, rightValue any
func evalLeftShift(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
// if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
// return
// }
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
// if IsList(leftValue) {
// list, _ := leftValue.(*ListType)
// newList := append(*list, rightValue)
// v = &newList
// if
// } else {
// err = self.errIncompatibleTypes(leftValue, rightValue)
// }
// return
// }
v, err = bitLeftShift(opTerm, leftValue, rightValue)
return
}
// init
func init() {
+8 -4
View File
@@ -4,6 +4,10 @@
// operator-sign.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- plus sign term
func newPlusSignTerm(tk *Token) (inst *term) {
@@ -28,21 +32,21 @@ func newMinusSignTerm(tk *Token) (inst *term) {
}
}
func evalSign(ctx ExprContext, opTerm *term) (v any, err error) {
func evalSign(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var rightValue any
if rightValue, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if IsFloat(rightValue) {
if kern.IsFloat(rightValue) {
if opTerm.tk.Sym == SymChangeSign {
f, _ := rightValue.(float64)
v = -f
} else {
v = rightValue
}
} else if IsInteger(rightValue) {
} else if kern.IsInteger(rightValue) {
if opTerm.tk.Sym == SymChangeSign {
i, _ := rightValue.(int64)
v = -i
@@ -50,7 +54,7 @@ func evalSign(ctx ExprContext, opTerm *term) (v any, err error) {
v = rightValue
}
} else {
err = opTerm.errIncompatibleType(rightValue)
err = opTerm.errIncompatiblePrefixPostfixType(rightValue)
}
return
}
+33 -31
View File
@@ -7,6 +7,8 @@ package expr
import (
"fmt"
"slices"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- plus term
@@ -22,46 +24,46 @@ func newPlusTerm(tk *Token) (inst *term) {
}
func sumValues(plusTerm *term, leftValue, rightValue any) (v any, err error) {
if (IsString(leftValue) && isNumberString(rightValue)) || (IsString(rightValue) && isNumberString(leftValue)) {
if (kern.IsString(leftValue) && kern.IsNumberString(rightValue)) || (kern.IsString(rightValue) && kern.IsNumberString(leftValue)) {
v = fmt.Sprintf("%v%v", leftValue, rightValue)
} else if IsNumber(leftValue) && IsNumber(rightValue) {
if IsFloat(leftValue) || IsFloat(rightValue) {
v = numAsFloat(leftValue) + numAsFloat(rightValue)
} else if kern.IsNumber(leftValue) && kern.IsNumber(rightValue) {
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
v = kern.NumAsFloat(leftValue) + kern.NumAsFloat(rightValue)
} else {
leftInt, _ := leftValue.(int64)
rightInt, _ := rightValue.(int64)
v = leftInt + rightInt
}
} else if IsList(leftValue) && IsList(rightValue) {
var leftList, rightList *ListType
leftList, _ = leftValue.(*ListType)
rightList, _ = rightValue.(*ListType)
} else if kern.IsList(leftValue) && kern.IsList(rightValue) {
var leftList, rightList *kern.ListType
leftList, _ = leftValue.(*kern.ListType)
rightList, _ = rightValue.(*kern.ListType)
sumList := make(ListType, 0, len(*leftList)+len(*rightList))
sumList := make(kern.ListType, 0, len(*leftList)+len(*rightList))
sumList = append(sumList, *leftList...)
sumList = append(sumList, *rightList...)
v = &sumList
} else if (isFraction(leftValue) && IsNumber(rightValue)) || (isFraction(rightValue) && IsNumber(leftValue)) {
if IsFloat(leftValue) || IsFloat(rightValue) {
v = numAsFloat(leftValue) + numAsFloat(rightValue)
} else if (kern.IsFraction(leftValue) && kern.IsNumber(rightValue)) || (kern.IsFraction(rightValue) && kern.IsNumber(leftValue)) {
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
v = kern.NumAsFloat(leftValue) + kern.NumAsFloat(rightValue)
} else {
v, err = sumAnyFract(leftValue, rightValue)
v, err = kern.SumAnyFract(leftValue, rightValue)
}
} else if IsDict(leftValue) && IsDict(rightValue) {
leftDict, _ := leftValue.(*DictType)
rightDict, _ := rightValue.(*DictType)
c := leftDict.clone()
c.merge(rightDict)
} else if kern.IsDict(leftValue) && kern.IsDict(rightValue) {
leftDict, _ := leftValue.(*kern.DictType)
rightDict, _ := rightValue.(*kern.DictType)
c := leftDict.Clone()
c.Merge(rightDict)
v = c
} else if isFraction(leftValue) && isFraction(rightValue) {
v, err = sumAnyFract(leftValue, rightValue)
} else if kern.IsFraction(leftValue) && kern.IsFraction(rightValue) {
v, err = kern.SumAnyFract(leftValue, rightValue)
} else {
err = plusTerm.errIncompatibleTypes(leftValue, rightValue)
}
return v, err
}
func evalPlus(ctx ExprContext, plusTerm *term) (v any, err error) {
func evalPlus(ctx kern.ExprContext, plusTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = plusTerm.evalInfix(ctx); err != nil {
@@ -84,20 +86,20 @@ func newMinusTerm(tk *Token) (inst *term) {
}
func diffValues(minusTerm *term, leftValue, rightValue any) (v any, err error) {
if isNumOrFract(leftValue) && isNumOrFract(rightValue) {
if IsFloat(leftValue) || IsFloat(rightValue) {
v = numAsFloat(leftValue) - numAsFloat(rightValue)
} else if isFraction(leftValue) || isFraction(rightValue) {
v, err = subAnyFract(leftValue, rightValue)
if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
v = kern.NumAsFloat(leftValue) - kern.NumAsFloat(rightValue)
} else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) {
v, err = kern.SubAnyFract(leftValue, rightValue)
} else {
leftInt, _ := leftValue.(int64)
rightInt, _ := rightValue.(int64)
v = leftInt - rightInt
}
} else if IsList(leftValue) && IsList(rightValue) {
leftList, _ := leftValue.(*ListType)
rightList, _ := rightValue.(*ListType)
diffList := make(ListType, 0, len(*leftList)-len(*rightList))
} else if kern.IsList(leftValue) && kern.IsList(rightValue) {
leftList, _ := leftValue.(*kern.ListType)
rightList, _ := rightValue.(*kern.ListType)
diffList := make(kern.ListType, 0, len(*leftList)-len(*rightList))
for _, item := range *leftList {
if slices.Index(*rightList, item) < 0 {
diffList = append(diffList, item)
@@ -110,7 +112,7 @@ func diffValues(minusTerm *term, leftValue, rightValue any) (v any, err error) {
return
}
func evalMinus(ctx ExprContext, minusTerm *term) (v any, err error) {
func evalMinus(ctx kern.ExprContext, minusTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = minusTerm.evalInfix(ctx); err != nil {
+10 -6
View File
@@ -4,7 +4,11 @@
// operator-unset.go
package expr
import "strings"
import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- unset term
@@ -18,7 +22,7 @@ func newUnsetTerm(tk *Token) (inst *term) {
}
}
func deleteContextItem(ctx ExprContext, opTerm *term, item any) (deleted bool, err error) {
func deleteContextItem(ctx kern.ExprContext, opTerm *term, item any) (deleted bool, err error) {
if name, ok := item.(string); ok {
var size int
if strings.HasSuffix(name, "()") {
@@ -31,12 +35,12 @@ func deleteContextItem(ctx ExprContext, opTerm *term, item any) (deleted bool, e
deleted = ctx.VarCount() < size
}
} else {
err = opTerm.errIncompatibleType(item)
err = opTerm.errIncompatiblePrefixPostfixType(item)
}
return
}
func evalUnset(ctx ExprContext, opTerm *term) (v any, err error) {
func evalUnset(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var childValue any
var deleted bool
@@ -45,8 +49,8 @@ func evalUnset(ctx ExprContext, opTerm *term) (v any, err error) {
}
count := 0
if IsList(childValue) {
list, _ := childValue.(*ListType)
if kern.IsList(childValue) {
list, _ := childValue.(*kern.ListType)
for _, item := range *list {
if deleted, err = deleteContextItem(ctx, opTerm, item); err != nil {
break
+32 -16
View File
@@ -104,7 +104,7 @@ func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) {
param := newTerm(tk)
if len(args) > 0 {
if pos := paramAlreadyDefined(args, param); pos > 0 {
err = tk.Errorf("parameter %q at position %d already defined at position %d", param.source(), len(args)+1, pos)
err = tk.Errorf("parameter %q at position %d already defined at position %d", param.Source(), len(args)+1, pos)
break
}
}
@@ -155,7 +155,7 @@ func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) {
func paramAlreadyDefined(args []*term, param *term) (position int) {
position = 0
for i, arg := range args {
if arg.source() == param.source() {
if arg.Source() == param.Source() {
position = i + 1
}
}
@@ -397,7 +397,7 @@ func couldBeACollection(t *term) bool {
func listSubTree(tree *ast, listTerm *term, allowIndeces bool) (root *term, err error) {
var tk *Token
if allowIndeces {
tk = NewToken(listTerm.tk.row, listTerm.tk.col, SymIndex, listTerm.source())
tk = NewToken(listTerm.tk.row, listTerm.tk.col, SymIndex, listTerm.Source())
root = newTerm(tk)
if err = tree.addTerm(root); err == nil {
err = tree.addTerm(listTerm)
@@ -409,6 +409,23 @@ func listSubTree(tree *ast, listTerm *term, allowIndeces bool) (root *term, err
return
}
func changePrefix(tk *Token) {
switch tk.Sym {
case SymMinus:
tk.SetSymbol(SymChangeSign)
case SymPlus:
tk.SetSymbol(SymUnchangeSign)
case SymStar:
tk.SetSymbol(SymDereference)
case SymExclamation:
tk.SetSymbol(SymNot)
case SymDoublePlus:
tk.SetSymbol(SymPreInc)
case SymDoubleMinus:
tk.SetSymbol(SymPreDec)
}
}
func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymbols ...Symbol) (tree *ast, err error) {
var selectorTerm *term = nil
var currentTerm *term = nil
@@ -437,14 +454,16 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
//fmt.Println("Token:", tk)
if firstToken {
if tk.Sym == SymMinus {
tk.Sym = SymChangeSign
} else if tk.Sym == SymPlus {
tk.Sym = SymUnchangeSign
} else if tk.IsSymbol(SymExclamation) {
err = tk.Errorf("postfix opertor %q requires an operand on its left", tk)
break
}
changePrefix(tk)
// if tk.Sym == SymMinus {
// tk.Sym = SymChangeSign
// } else if tk.Sym == SymPlus {
// tk.Sym = SymUnchangeSign
// } else if tk.IsSymbol(SymStar) {
// tk.SetSymbol(SymDereference)
// } else if tk.IsSymbol(SymExclamation) {
// tk.SetSymbol(SymNot)
// }
firstToken = false
}
@@ -481,7 +500,7 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
currentTerm = mapTerm
}
}
case SymEqual, SymPlusEqual, SymMinusEqual, SymStarEqual, SymSlashEqual, SymPercEqual:
case SymEqual, SymPlusEqual, SymMinusEqual, SymStarEqual, SymSlashEqual, SymPercEqual, SymAmpersandEqual, SymVertBarEqual, SymDoubleLessEqual, SymDoubleGreaterEqual, SymCaretEqual:
currentTerm, err = tree.addToken(tk)
firstToken = true
case SymFuncDef:
@@ -518,15 +537,12 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
}
}
} else {
// if hasFlag(ctx, allowIndex) {
// tk.Sym = SymRange
// }
currentTerm, err = tree.addToken(tk)
}
if tk.IsOneOfA(SymColon, SymRange) {
// Colon outside a selector term acts like a separator
firstToken = true
}
}
default:
currentTerm, err = tree.addToken(tk)
}
+22 -16
View File
@@ -10,6 +10,8 @@ import (
"os"
"plugin"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
var pluginRegister map[string]*plugin.Plugin
@@ -31,20 +33,20 @@ func pluginExists(name string) (exists bool) {
func makePluginName(name string) (decorated string) {
var template string
if execName, err := os.Executable(); err != nil || !strings.Contains(execName, "debug") {
template = "expr-%s-plugin.so"
template = "expr-%s-plugin%s"
} else {
template = "expr-%s-plugin.so.debug"
template = "expr-%s-plugin%s.debug"
}
decorated = fmt.Sprintf(template, name)
decorated = fmt.Sprintf(template, name, SHAREDLIBRARY_EXTENSION)
return
}
func importPlugin( /*ctx ExprContext,*/ dirList []string, name string) (err error) {
func importPlugin(ctx kern.ExprContext, dirList []string, name string) (err error) {
var filePath string
var p *plugin.Plugin
var sym plugin.Symbol
var moduleName string
var importFunc func(ExprContext)
var importFunc func(kern.ExprContext)
var ok bool
decoratedName := makePluginName(name)
@@ -71,7 +73,7 @@ func importPlugin( /*ctx ExprContext,*/ dirList []string, name string) (err erro
}
if deps := *sym.(*[]string); len(deps) > 0 {
// var count int
if err = loadModules(dirList, deps); err != nil {
if err = loadModules(ctx, dirList, deps); err != nil {
return
}
}
@@ -80,31 +82,35 @@ func importPlugin( /*ctx ExprContext,*/ dirList []string, name string) (err erro
return
}
if importFunc, ok = sym.(func(ExprContext)); !ok {
if importFunc, ok = sym.(func(kern.ExprContext)); !ok {
err = fmt.Errorf("plugin %q does not provide a valid import function", decoratedName)
return
}
registerPlugin(moduleName, p)
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
importFunc(globalCtx)
}
return
}
func importPluginFromSearchPath(name any) (count int, err error) {
func importPluginFromSearchPath(ctx kern.ExprContext, name any) (count int, err error) {
var moduleSpec any
dirList := buildSearchDirList("plugin", ENV_EXPR_PLUGIN_PATH)
var it kern.Iterator
dirList := buildSearchDirList(ctx, "plugin", ENV_EXPR_PLUGIN_PATH)
count = 0
it := NewAnyIterator(name)
if it, err = NewIterator(name); err != nil {
return
}
for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() {
if module, ok := moduleSpec.(string); ok {
if err = importPlugin(dirList, module); err != nil {
if err = importPlugin(ctx, dirList, module); err != nil {
break
}
count++
} else {
err = fmt.Errorf("expected string as item nr %d, got %s", it.Index()+1, TypeName(moduleSpec))
err = fmt.Errorf("expected string as item nr %d, got %s", it.Index()+1, kern.TypeName(moduleSpec))
break
}
}
@@ -114,10 +120,10 @@ func importPluginFromSearchPath(name any) (count int, err error) {
return
}
func loadModules(dirList []string, moduleNames []string) (err error) {
func loadModules(ctx kern.ExprContext, dirList []string, moduleNames []string) (err error) {
for _, name := range moduleNames {
if err1 := importPlugin(dirList, name); err1 != nil {
if !ImportInContext(name) {
if err1 := importPlugin(ctx, dirList, name); err1 != nil {
if !ImportInContext(ctx, name) {
err = err1
break
}
+54 -7
View File
@@ -11,6 +11,8 @@ import (
"io"
"strconv"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
type scanner struct {
@@ -169,13 +171,19 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
case '|':
if next, _ := scanner.peek(); next == '|' {
tk = scanner.moveOn(SymDoubleVertBar, ch, next)
} else if next, _ = scanner.peek(); next == '=' {
tk = scanner.moveOn(SymVertBarEqual, ch, next)
} else {
tk = scanner.makeToken(SymVertBar, ch)
}
case ',':
tk = scanner.makeToken(SymComma, ch)
case '^':
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymCaretEqual, ch, next)
} else {
tk = scanner.makeToken(SymCaret, ch)
}
case ':':
if next, _ := scanner.peek(); next == ':' {
tk = scanner.moveOn(SymDoubleColon, ch, next)
@@ -204,14 +212,14 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
tk = scanner.makeToken(SymQuote, ch)
escape = false
} else {
tk = scanner.fetchString(ch)
tk = scanner.fetchString(ch, true)
}
case '"':
if escape {
tk = scanner.makeToken(SymDoubleQuote, ch)
escape = false
} else {
tk = scanner.fetchString(ch)
tk = scanner.fetchString(ch, true)
}
case '`':
tk = scanner.makeToken(SymBackTick, ch)
@@ -234,11 +242,17 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
case '&':
if next, _ := scanner.peek(); next == '&' {
tk = scanner.moveOn(SymDoubleAmpersand, ch, next)
} else if next, _ = scanner.peek(); next == '=' {
tk = scanner.moveOn(SymAmpersandEqual, ch, next)
} else {
tk = scanner.makeToken(SymAmpersand, ch)
}
case '%':
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymPercEqual, ch, next)
} else {
tk = scanner.makeToken(SymPercent, ch)
}
case '#':
tk = scanner.makeToken(SymHash, ch)
case '@':
@@ -267,7 +281,14 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymLessOrEqual, ch, next)
} else if next == '<' {
tk = scanner.moveOn(SymDoubleLess, ch, next)
scanner.readChar()
next2, _ := scanner.readChar()
scanner.unreadChar()
if next2 == '=' {
tk = scanner.moveOn(SymDoubleLessEqual, ch, next, next2)
} else {
tk = scanner.accept(SymDoubleLess, ch, next)
}
} else if next == '>' {
tk = scanner.moveOn(SymLessGreater, ch, next)
} else if next == '+' {
@@ -279,7 +300,14 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymGreaterOrEqual, ch, next)
} else if next == '>' {
tk = scanner.moveOn(SymDoubleGreater, ch, next)
scanner.readChar()
next2, _ := scanner.readChar()
scanner.unreadChar()
if next2 == '=' {
tk = scanner.moveOn(SymDoubleGreaterEqual, ch, next, next2)
} else {
tk = scanner.accept(SymDoubleGreater, ch, next)
}
} else {
tk = scanner.makeToken(SymGreater, ch)
}
@@ -289,6 +317,14 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
tk.source += ")"
} else if next == '$' {
tk = scanner.moveOn(SymDoubleDollar, ch, next)
} else if next == '{' {
scanner.readChar()
if tk = scanner.fetchString('}', false); tk != nil {
tk.Sym = SymIdentifier
}
} else if next == '_' || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') {
scanner.readChar()
tk = scanner.fetchIdentifier(next)
} else {
tk = scanner.makeToken(SymDollar, ch)
}
@@ -469,7 +505,7 @@ func (scanner *scanner) parseNumber(firstCh byte) (tk *Token) {
if sym == SymFloat {
value, err = strconv.ParseFloat(txt, 64)
} else if sym == SymFraction {
value, err = makeGeneratingFraction(txt)
value, err = kern.MakeGeneratingFraction(txt)
} else {
value, err = strconv.ParseInt(txt, numBase, 64)
}
@@ -564,7 +600,7 @@ func (scanner *scanner) fetchUntil(sym Symbol, allowEos bool, endings ...byte) (
return
}
func (scanner *scanner) fetchString(termCh byte) (tk *Token) {
func (scanner *scanner) fetchString(termCh byte, addQuote bool) (tk *Token) {
var err error
var ch, prev byte
var sb strings.Builder
@@ -602,7 +638,11 @@ func (scanner *scanner) fetchString(termCh byte) (tk *Token) {
}
} else {
txt := sb.String()
if addQuote {
tk = scanner.makeValueToken(SymString, `"`+txt+`"`, txt)
} else {
tk = scanner.makeValueToken(SymString, txt, txt)
}
}
return
}
@@ -634,9 +674,16 @@ func (scanner *scanner) translate(sym Symbol) Symbol {
func (scanner *scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
for i := 1; i < len(chars); i++ {
// for i := 1; i < len(chars); i++ {
if len(chars) > 1 {
scanner.readChar()
}
// }
return
}
func (scanner *scanner) accept(sym Symbol, chars ...byte) (tk *Token) {
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
return
}
+80 -27
View File
@@ -7,38 +7,62 @@ package expr
import (
"fmt"
"slices"
"git.portale-stac.it/go-pkg/expr/kern"
// "strings"
)
type SimpleStore struct {
parent ExprContext
global kern.ExprContext
parent kern.ExprContext
varStore map[string]any
funcStore map[string]ExprFunc
funcStore map[string]kern.ExprFunc
}
func NewSimpleStore() *SimpleStore {
global := InitGlobal()
ctx := &SimpleStore{
global: global,
varStore: make(map[string]any),
funcStore: make(map[string]ExprFunc),
funcStore: make(map[string]kern.ExprFunc),
}
return ctx
}
func NewSimpleStoreWithoutGlobalContext() *SimpleStore {
ctx := &SimpleStore{
varStore: make(map[string]any),
funcStore: make(map[string]kern.ExprFunc),
}
return ctx
}
func (ss *SimpleStore) Init() {
ss.varStore = make(map[string]any)
ss.funcStore = make(map[string]kern.ExprFunc)
}
func filterRefName(name string) bool { return name[0] != '@' }
//func filterPrivName(name string) bool { return name[0] != '_' }
func (ctx *SimpleStore) SetParent(parentCtx ExprContext) {
func (ctx *SimpleStore) SetParent(parentCtx kern.ExprContext) {
ctx.parent = parentCtx
}
func (ctx *SimpleStore) GetParent() ExprContext {
func (ctx *SimpleStore) GetParent() kern.ExprContext {
return ctx.parent
}
func (ctx *SimpleStore) Clone() ExprContext {
func (ctx *SimpleStore) GetGlobal() (globalCtx kern.ExprContext) {
return ctx.global
}
func (ctx *SimpleStore) Clone() kern.ExprContext {
clone := &SimpleStore{
varStore: CloneFilteredMap(ctx.varStore, filterRefName),
funcStore: CloneFilteredMap(ctx.funcStore, filterRefName),
global: ctx.global,
varStore: kern.CloneFilteredMap(ctx.varStore, filterRefName),
funcStore: kern.CloneFilteredMap(ctx.funcStore, filterRefName),
}
return clone
}
@@ -52,19 +76,19 @@ func (ctx *SimpleStore) Clone() ExprContext {
// }
// }
func (ctx *SimpleStore) ToString(opt FmtOpt) string {
func (ctx *SimpleStore) ToString(opt kern.FmtOpt) string {
dict := ctx.ToDict()
return dict.ToString(opt)
}
func (ctx *SimpleStore) varsToDict(dict *DictType) *DictType {
func (ctx *SimpleStore) varsToDict(dict *kern.DictType) *kern.DictType {
names := ctx.EnumVars(nil)
slices.Sort(names)
for _, name := range ctx.EnumVars(nil) {
value, _ := ctx.GetVar(name)
if f, ok := value.(Formatter); ok {
if f, ok := value.(kern.Formatter); ok {
(*dict)[name] = f.ToString(0)
} else if _, ok = value.(Functor); ok {
} else if _, ok = value.(kern.Functor); ok {
(*dict)[name] = "func(){}"
} else {
(*dict)[name] = fmt.Sprintf("%v", value)
@@ -73,12 +97,12 @@ func (ctx *SimpleStore) varsToDict(dict *DictType) *DictType {
return dict
}
func (ctx *SimpleStore) funcsToDict(dict *DictType) *DictType {
func (ctx *SimpleStore) funcsToDict(dict *kern.DictType) *kern.DictType {
names := ctx.EnumFuncs(func(name string) bool { return true })
slices.Sort(names)
for _, name := range names {
value, _ := ctx.GetFuncInfo(name)
if formatter, ok := value.(Formatter); ok {
if formatter, ok := value.(kern.Formatter); ok {
(*dict)[name] = formatter.ToString(0)
} else {
(*dict)[name] = fmt.Sprintf("%v", value)
@@ -87,20 +111,23 @@ func (ctx *SimpleStore) funcsToDict(dict *DictType) *DictType {
return dict
}
func (ctx *SimpleStore) ToDict() (dict *DictType) {
dict = MakeDict()
(*dict)["variables"] = ctx.varsToDict(MakeDict())
(*dict)["functions"] = ctx.funcsToDict(MakeDict())
func (ctx *SimpleStore) ToDict() (dict *kern.DictType) {
dict = kern.MakeDict()
(*dict)["variables"] = ctx.varsToDict(kern.MakeDict())
(*dict)["functions"] = ctx.funcsToDict(kern.MakeDict())
return
}
func (ctx *SimpleStore) GetVar(varName string) (v any, exists bool) {
v, exists = ctx.varStore[varName]
func (ctx *SimpleStore) GetVar(varName string) (value any, exists bool) {
if value, exists = ctx.varStore[varName]; !exists && ctx.global != nil {
value, exists = ctx.global.GetVar(varName)
}
return
}
func (ctx *SimpleStore) GetLast() (v any) {
v = ctx.varStore["last"]
v = ctx.varStore[kern.ControlLastResult]
return
}
@@ -111,7 +138,7 @@ func (ctx *SimpleStore) UnsafeSetVar(varName string, value any) {
func (ctx *SimpleStore) SetVar(varName string, value any) {
// fmt.Printf("[%p] SetVar(%v, %v)\n", ctx, varName, value)
if allowedValue, ok := fromGenericAny(value); ok {
if allowedValue, ok := kern.FromGenericAny(value); ok {
ctx.varStore[varName] = allowedValue
} else {
panic(fmt.Errorf("unsupported type %T of value %v", value, value))
@@ -140,16 +167,42 @@ func (ctx *SimpleStore) DeleteVar(varName string) {
delete(ctx.varStore, varName)
}
func (ctx *SimpleStore) GetFuncInfo(name string) (info ExprFunc, exists bool) {
info, exists = ctx.funcStore[name]
func (ctx *SimpleStore) GetFuncInfo(name string) (info kern.ExprFunc, exists bool) {
info, exists, _ = ctx.GetFuncInfoAndOwner(name)
return
}
func (ctx *SimpleStore) RegisterFuncInfo(info ExprFunc) {
func (ctx *SimpleStore) GetFuncInfoAndOwner(name string) (info kern.ExprFunc, exists bool, ownerCtx kern.ExprContext) {
if len(name) > 0 {
if info, exists = ctx.GetLocalFuncInfo(name); exists {
ownerCtx = ctx
} else if globalCtx := ctx.GetGlobal(); globalCtx != nil {
if info, exists = globalCtx.GetFuncInfo(name); exists {
ownerCtx = globalCtx
}
}
}
return
}
func (ctx *SimpleStore) GetLocalFuncInfo(name string) (info kern.ExprFunc, exists bool) {
var v any
if len(name) > 0 {
if v, exists = ctx.GetVar(name); exists && kern.IsFunctor(v) {
f, _ := v.(kern.Functor)
info = f.GetFunc()
} else {
info, exists = ctx.funcStore[name]
}
}
return
}
func (ctx *SimpleStore) RegisterFuncInfo(info kern.ExprFunc) {
ctx.funcStore[info.Name()], _ = info.(*funcInfo)
}
func (ctx *SimpleStore) RegisterFunc(name string, functor Functor, returnType string, params []ExprFuncParam) (exprFunc ExprFunc, err error) {
func (ctx *SimpleStore) RegisterFunc(name string, functor kern.Functor, returnType string, params []kern.ExprFuncParam) (exprFunc kern.ExprFunc, err error) {
var info *funcInfo
if info, err = newFuncInfo(name, functor, returnType, params); err == nil {
ctx.funcStore[name] = info
@@ -181,7 +234,7 @@ func (ctx *SimpleStore) DeleteFunc(funcName string) {
}
func (ctx *SimpleStore) Call(name string, args map[string]any) (result any, err error) {
if info, exists := GetLocalFuncInfo(ctx, name); exists {
if info, exists := ctx.GetLocalFuncInfo(name); exists {
functor := info.Functor()
result, err = functor.InvokeNamed(ctx, name, args)
} else {
+100 -81
View File
@@ -14,7 +14,7 @@ type symbolClass int16
const (
symClassOperator symbolClass = iota
symClassPostOp
symClassCommand
symClassIdentifier
symClassDelimiter
symClassParenthesis
@@ -26,77 +26,85 @@ const (
type symbolSpec struct {
repr string
kind symbolClass
opType termPosition
}
func init() {
symbolMap = map[Symbol]symbolSpec{
SymUnknown: {"<unknown>", symClassOther}, // -1: Unknown symbol
SymNone: {"<null>", symClassOther}, // 0: Null value for variable of type symbol
SymError: {"<error>", symClassOther}, // 1: Error reading from stream
SymEos: {"<eos>", symClassOther}, // 2: End of stream
SymMinus: {"-", symClassOperator}, // 3: '-'
SymMinusEqual: {"-=", symClassOperator}, // 4: '-='
SymDoubleMinus: {"--", symClassOperator}, // 5: '--'
SymPlus: {"+", symClassOperator}, // 6: '+'
SymPlusEqual: {"+=", symClassOperator}, // 7: '+='
SymDoublePlus: {"++", symClassOperator}, // 8: '++'
SymStar: {"*", symClassOperator}, // 9: '*'
SymDoubleStar: {"**", symClassOperator}, // 10: '**'
SymSlash: {"/", symClassOperator}, // 11: '/'
SymBackSlash: {"\\", symClassOperator}, // 12: '\'
SymVertBar: {"|", symClassOperator}, // 13: '|'
SymDoubleVertBar: {"||", symClassOperator}, // 14: '||'
SymComma: {",", symClassOperator}, // 15: ','
SymColon: {":", symClassOperator}, // 16: ':'
SymSemiColon: {";", symClassOperator}, // 17: ';'
SymDot: {".", symClassOperator}, // 18: '.'
SymDotSlash: {"./", symClassOperator}, // 19: './'
SymQuote: {"'", symClassDelimiter}, // 20: '\''
SymDoubleQuote: {"\"", symClassDelimiter}, // 21: '"'
SymBackTick: {"`", symClassOperator}, // 22: '`'
SymExclamation: {"!", symClassPostOp}, // 23: '!'
SymQuestion: {"?", symClassOperator}, // 24: '?'
SymAmpersand: {"&", symClassOperator}, // 25: '&'
SymDoubleAmpersand: {"&&", symClassOperator}, // 26: '&&'
SymPercent: {"%", symClassOperator}, // 27: '%'
SymAt: {"@", symClassOperator}, // 28: '@'
SymUndescore: {"_", symClassOperator}, // 29: '_'
SymEqual: {"=", symClassOperator}, // 30: '='
SymDoubleEqual: {"==", symClassOperator}, // 31: '=='
SymLess: {"<", symClassOperator}, // 32: '<'
SymLessOrEqual: {"<=", symClassOperator}, // 33: '<='
SymGreater: {">", symClassOperator}, // 34: '>'
SymGreaterOrEqual: {">=", symClassOperator}, // 35: '>='
SymLessGreater: {"<>", symClassOperator}, // 36: '<>'
SymNotEqual: {"!=", symClassOperator}, // 37: '!='
SymDollar: {"$", symClassOperator}, // 38: '$'
SymHash: {"#", symClassOperator}, // 39: '#'
SymOpenRound: {"(", symClassParenthesis}, // 40: '('
SymClosedRound: {")", symClassParenthesis}, // 41: ')'
SymOpenSquare: {"[", symClassParenthesis}, // 42: '['
SymClosedSquare: {"]", symClassParenthesis}, // 43: ']'
SymOpenBrace: {"{", symClassParenthesis}, // 44: '{'
SymClosedBrace: {"}", symClassParenthesis}, // 45: '}'
SymTilde: {"~", symClassOperator}, // 46: '~'
SymDoubleQuestion: {"??", symClassOperator}, // 47: '??'
SymQuestionEqual: {"?=", symClassOperator}, // 48: '?='
SymQuestionExclam: {"?!", symClassOperator}, // 49: '?!'
SymDoubleAt: {"@@", symClassOperator}, // 50: '@@'
SymDoubleColon: {"::", symClassOperator}, // 51: '::'
SymDoubleGreater: {">>", symClassOperator}, // 52: '>>'
SymDoubleLess: {"<<", symClassOperator}, // 53: '<<'
SymCaret: {"^", symClassOperator}, // 54: '^'
SymDollarRound: {"$(", symClassOperator}, // 55: '$('
SymOpenClosedRound: {"()", symClassPostOp}, // 56: '()'
SymDoubleDollar: {"$$", symClassOperator}, // 57: '$$'
SymDoubleDot: {"..", symClassOperator}, // 58: '..'
SymTripleDot: {"...", symClassOperator}, // 59: '...'
SymStarEqual: {"*=", symClassOperator}, // 60: '*='
SymSlashEqual: {"/=", symClassOperator}, // 61: '/='
SymPercEqual: {"%=", symClassOperator}, // 62: '%='
SymPlusGreater: {"+>", symClassOperator}, // 63: '+>'
SymLessPlus: {"<+", symClassOperator}, // 64: '<+'
SymUnknown: {"<unknown>", symClassOther, posLeaf}, // -1: Unknown symbol
SymNone: {"<null>", symClassOther, posLeaf}, // 0: Null value for variable of type symbol
SymError: {"<error>", symClassOther, posLeaf}, // 1: Error reading from stream
SymEos: {"<eos>", symClassOther, posLeaf}, // 2: End of stream
SymMinus: {"-", symClassOperator, posInfix}, // 3: '-'
SymMinusEqual: {"-=", symClassOperator, posInfix}, // 4: '-='
SymDoubleMinus: {"--", symClassOperator, posPostfix}, // 5: '--'
SymPlus: {"+", symClassOperator, posInfix}, // 6: '+'
SymPlusEqual: {"+=", symClassOperator, posInfix}, // 7: '+='
SymDoublePlus: {"++", symClassOperator, posPostfix}, // 8: '++'
SymStar: {"*", symClassOperator, posInfix}, // 9: '*'
SymDoubleStar: {"**", symClassOperator, posInfix}, // 10: '**'
SymSlash: {"/", symClassOperator, posInfix}, // 11: '/'
SymBackSlash: {"\\", symClassOperator, posLeaf}, // 12: '\'
SymVertBar: {"|", symClassOperator, posInfix}, // 13: '|'
SymDoubleVertBar: {"||", symClassOperator, posInfix}, // 14: '||'
SymComma: {",", symClassOperator, posInfix}, // 15: ','
SymColon: {":", symClassOperator, posInfix}, // 16: ':'
SymSemiColon: {";", symClassOperator, posInfix}, // 17: ';'
SymDot: {".", symClassOperator, posInfix}, // 18: '.'
SymDotSlash: {"./", symClassOperator, posInfix}, // 19: './'
SymQuote: {"'", symClassDelimiter, posLeaf}, // 20: '\''
SymDoubleQuote: {"\"", symClassDelimiter, posLeaf}, // 21: '"'
SymBackTick: {"`", symClassDelimiter, posLeaf}, // 22: '`'
SymExclamation: {"!", symClassOperator, posPostfix}, // 23: '!'
SymQuestion: {"?", symClassOperator, posInfix}, // 24: '?'
SymAmpersand: {"&", symClassOperator, posInfix}, // 25: '&'
SymDoubleAmpersand: {"&&", symClassOperator, posInfix}, // 26: '&&'
SymPercent: {"%", symClassOperator, posInfix}, // 27: '%'
SymAt: {"@", symClassOperator, posPrefix}, // 28: '@'
SymUndescore: {"_", symClassIdentifier, posLeaf}, // 29: '_'
SymEqual: {"=", symClassOperator, posInfix}, // 30: '='
SymDoubleEqual: {"==", symClassOperator, posInfix}, // 31: '=='
SymLess: {"<", symClassOperator, posInfix}, // 32: '<'
SymLessOrEqual: {"<=", symClassOperator, posInfix}, // 33: '<='
SymGreater: {">", symClassOperator, posInfix}, // 34: '>'
SymGreaterOrEqual: {">=", symClassOperator, posInfix}, // 35: '>='
SymLessGreater: {"<>", symClassOperator, posInfix}, // 36: '<>'
SymNotEqual: {"!=", symClassOperator, posInfix}, // 37: '!='
SymDollar: {"$", symClassOperator, posPrefix}, // 38: '$'
SymHash: {"#", symClassOperator, posPrefix}, // 39: '#'
SymOpenRound: {"(", symClassParenthesis, posPrefix}, // 40: '('
SymClosedRound: {")", symClassParenthesis, posPostfix}, // 41: ')'
SymOpenSquare: {"[", symClassParenthesis, posPrefix}, // 42: '['
SymClosedSquare: {"]", symClassParenthesis, posPostfix}, // 43: ']'
SymOpenBrace: {"{", symClassParenthesis, posPrefix}, // 44: '{'
SymClosedBrace: {"}", symClassParenthesis, posPostfix}, // 45: '}'
SymTilde: {"~", symClassOperator, posPrefix}, // 46: '~'
SymDoubleQuestion: {"??", symClassOperator, posInfix}, // 47: '??'
SymQuestionEqual: {"?=", symClassOperator, posInfix}, // 48: '?='
SymQuestionExclam: {"?!", symClassOperator, posInfix}, // 49: '?!'
SymDoubleAt: {"@@", symClassCommand, posLeaf}, // 50: '@@'
SymDoubleColon: {"::", symClassOperator, posInfix}, // 51: '::'
SymDoubleGreater: {">>", symClassOperator, posInfix}, // 52: '>>'
SymDoubleLess: {"<<", symClassOperator, posInfix}, // 53: '<<'
SymCaret: {"^", symClassOperator, posInfix}, // 54: '^'
SymDollarRound: {"$(", symClassOperator, posPrefix}, // 55: '$('
SymOpenClosedRound: {"()", symClassOperator, posPostfix}, // 56: '()'
SymDoubleDollar: {"$$", symClassCommand, posLeaf}, // 57: '$$'
SymDoubleDot: {"..", symClassOperator, posInfix}, // 58: '..'
SymTripleDot: {"...", symClassOperator, posPostfix}, // 59: '...'
SymStarEqual: {"*=", symClassOperator, posInfix}, // 60: '*='
SymSlashEqual: {"/=", symClassOperator, posInfix}, // 61: '/='
SymPercEqual: {"%=", symClassOperator, posInfix}, // 62: '%='
SymDoubleLessEqual: {"<<=", symClassOperator, posInfix}, // 63: '<<='
SymDoubleGreaterEqual: {">>=", symClassOperator, posInfix}, // 64: '>>='
SymAmpersandEqual: {"&=", symClassOperator, posInfix}, // 65: '&='
SymVertBarEqual: {"|=", symClassOperator, posInfix}, // 65: '|='
SymCaretEqual: {"^=", symClassOperator, posInfix}, // 66: '^='
SymPlusGreater: {"+>", symClassOperator, posInfix}, // 67: '+>'
SymLessPlus: {"<+", symClassOperator, posInfix}, // 68: '<+'
SymPreInc: {"++", symClassOperator, posPrefix}, // : '++'
SymPreDec: {"--", symClassOperator, posPrefix}, // : '--'
// SymChangeSign
// SymUnchangeSign
// SymIdentifier
@@ -123,17 +131,21 @@ func init() {
// // SymClosedComment // 0: '*/'
// // SymOneLineComment // 0: '//'
// keywordBase
SymKwAnd: {"and", symClassOperator},
SymKwNot: {"not", symClassOperator},
SymKwOr: {"or", symClassOperator},
SymKwBut: {"but", symClassOperator},
SymKwFunc: {"func(", symClassDeclaration},
SymKwBuiltin: {"builtin", symClassOperator},
SymKwPlugin: {"plugin", symClassOperator},
SymKwIn: {"in", symClassOperator},
SymKwInclude: {"include", symClassOperator},
SymKwNil: {"nil", symClassValue},
SymKwUnset: {"unset", symClassOperator},
SymKwAnd: {"and", symClassOperator, posInfix},
SymKwNot: {"not", symClassOperator, posInfix},
SymKwOr: {"or", symClassOperator, posInfix},
SymKwBut: {"but", symClassOperator, posInfix},
SymKwMap: {"map", symClassOperator, posInfix},
SymKwFilter: {"filter", symClassOperator, posInfix},
SymKwDigest: {"digest", symClassOperator, posInfix},
SymKwJoin: {"join", symClassOperator, posInfix},
SymKwFunc: {"func(", symClassDeclaration, posPrefix},
SymKwBuiltin: {"builtin", symClassOperator, posPrefix},
SymKwPlugin: {"plugin", symClassOperator, posPrefix},
SymKwIn: {"in", symClassOperator, posInfix},
SymKwInclude: {"include", symClassOperator, posPrefix},
SymKwNil: {"nil", symClassValue, posLeaf},
SymKwUnset: {"unset", symClassOperator, posPrefix},
}
}
@@ -171,12 +183,19 @@ func StringEndsWithOperator(s string) bool {
}
func endingOperator(s string) (sym Symbol) {
var matchLength = 0
sym = SymNone
lower := strings.ToLower(s)
lower := strings.TrimRight(strings.ToLower(s), " \t")
for symbol, spec := range symbolMap {
if spec.kind == symClassOperator && strings.HasSuffix(lower, spec.repr) {
if strings.HasSuffix(lower, spec.repr) {
if len(spec.repr) > matchLength {
matchLength = len(spec.repr)
if spec.kind == symClassOperator && (spec.opType == posInfix || spec.opType == posPrefix) {
sym = symbol
break
} else {
sym = SymNone
}
}
}
}
return
+18 -2
View File
@@ -71,10 +71,18 @@ const (
SymStarEqual // 60: '*='
SymSlashEqual // 61: '/='
SymPercEqual // 62: '%='
SymPlusGreater // 63: '+>'
SymLessPlus // 64: '<+'
SymDoubleLessEqual // 63: '<<='
SymDoubleGreaterEqual // 64: '>>='
SymAmpersandEqual // 65: '&='
SymVertBarEqual // 65: '|='
SymCaretEqual // 66: '^='
SymPlusGreater // 67: '+>'
SymLessPlus // 68: '<+'
SymChangeSign
SymUnchangeSign
SymDereference
SymPreInc
SymPreDec
SymIdentifier
SymBool
SymInteger
@@ -111,6 +119,10 @@ const (
SymKwPlugin
SymKwIn
SymKwInclude
SymKwMap
SymKwFilter
SymKwDigest
SymKwJoin
SymKwNil
SymKwUnset
)
@@ -127,9 +139,13 @@ func init() {
"FUNC": SymKwFunc,
"IN": SymKwIn,
"INCLUDE": SymKwInclude,
"MAP": SymKwMap,
"FILTER": SymKwFilter,
"NOT": SymKwNot,
"OR": SymKwOr,
"NIL": SymKwNil,
"UNSET": SymKwUnset,
"DIGEST": SymKwDigest,
"JOIN": SymKwJoin,
}
}
+9 -6
View File
@@ -7,6 +7,8 @@ package expr
import (
"errors"
"testing"
"git.portale-stac.it/go-pkg/expr/kern"
)
func TestBool(t *testing.T) {
@@ -19,19 +21,20 @@ func TestBool(t *testing.T) {
/* 5 */ {`not "true"`, false, nil},
/* 6 */ {`not "false"`, false, nil},
/* 7 */ {`not ""`, true, nil},
/* 8 */ {`not []`, nil, errors.New(`[1:4] prefix/postfix operator "NOT" do not support operand '[]' [list]`)},
/* 8 */ {`not []`, nil, errors.New(`[1:4] prefix/postfix operator "NOT" does not support operand '[]' [list]`)},
/* 9 */ {`true and false`, false, nil},
/* 10 */ {`true and []`, nil, errors.New(`[1:9] left operand 'true' [bool] and right operand '[]' [list] are not compatible with operator "AND"`)},
/* 11 */ {`[] and false`, nil, errors.New(`got list as left operand type of 'AND' operator, it must be bool`)},
/* 11 */ {`[] and false`, nil, errors.New(`[1:7] operator "AND" does not support operand '[]' [list] on its left side`)},
/* 12 */ {`true or false`, true, nil},
/* 13 */ {`true or []`, true, nil},
/* 14 */ {`[] or false`, nil, errors.New(`got list as left operand type of 'OR' operator, it must be bool`)},
/* 15 */ {`!true`, false, nil},
/* 13 */ //{`true or []`, nil, errors.New(`[1:8] left operand 'true' [bool] and right operand '[]' [list] are not compatible with operator "OR"`)},
}
// t.Setenv("EXPR_PATH", ".")
// runTestSuiteSpec(t, section, inputs, 1)
// runTestSuiteSpec(t, section, inputs, 13)
runTestSuite(t, section, inputs)
}
@@ -45,7 +48,7 @@ func TestBoolNoShortcut(t *testing.T) {
/* 5 */ {`not "true"`, false, nil},
/* 6 */ {`not "false"`, false, nil},
/* 7 */ {`not ""`, true, nil},
/* 8 */ {`not []`, nil, `[1:4] prefix/postfix operator "NOT" do not support operand '[]' [list]`},
/* 8 */ {`not []`, nil, `[1:4] prefix/postfix operator "NOT" does not support operand '[]' [list]`},
/* 9 */ {`true and false`, false, nil},
/* 10 */ {`true and []`, nil, `[1:9] left operand 'true' [bool] and right operand '[]' [list] are not compatible with operator "AND"`},
/* 11 */ {`[] and false`, nil, `[1:7] left operand '[]' [list] and right operand 'false' [bool] are not compatible with operator "AND"`},
@@ -57,10 +60,10 @@ func TestBoolNoShortcut(t *testing.T) {
// t.Setenv("EXPR_PATH", ".")
ctx := NewSimpleStore()
current := SetCtrl(ctx, ControlBoolShortcut, false)
current := kern.SetCtrl(ctx, kern.ControlBoolShortcut, false)
// runCtxTestSuiteSpec(t, ctx, section, inputs, 1)
runCtxTestSuite(t, ctx, section, inputs)
SetCtrl(ctx, ControlBoolShortcut, current)
kern.SetCtrl(ctx, kern.ControlBoolShortcut, current)
}
+19 -12
View File
@@ -6,6 +6,8 @@ package expr
import (
"testing"
"git.portale-stac.it/go-pkg/expr/kern"
)
func TestFuncBase(t *testing.T) {
@@ -33,10 +35,10 @@ func TestFuncBase(t *testing.T) {
/* 19 */ {`isFract(1:3)`, true, nil},
/* 20 */ {`isFract(3:1)`, false, nil},
/* 21 */ {`isRational(3:1)`, true, nil},
/* 22 */ {`fract("2.2(3)")`, newFraction(67, 30), nil},
/* 23 */ {`fract("1.21(3)")`, newFraction(91, 75), nil},
/* 24 */ {`fract(1.21(3))`, newFraction(91, 75), nil},
/* 25 */ {`fract(1.21)`, newFraction(121, 100), nil},
/* 22 */ {`fract("2.2(3)")`, kern.NewFraction(67, 30), nil},
/* 23 */ {`fract("1.21(3)")`, kern.NewFraction(91, 75), nil},
/* 24 */ {`fract(1.21(3))`, kern.NewFraction(91, 75), nil},
/* 25 */ {`fract(1.21)`, kern.NewFraction(121, 100), nil},
/* 26 */ {`dec(2)`, float64(2), nil},
/* 27 */ {`dec(2.0)`, float64(2), nil},
/* 28 */ {`dec("2.0")`, float64(2), nil},
@@ -45,23 +47,28 @@ func TestFuncBase(t *testing.T) {
/* 31 */ {`dec()`, nil, `dec(): too few params -- expected 1, got 0`},
/* 32 */ {`dec(1,2,3)`, nil, `dec(): too many params -- expected 1, got 3`},
/* 33 */ {`isBool(false)`, true, nil},
/* 34 */ {`fract(1:2)`, newFraction(1, 2), nil},
/* 35 */ {`fract(12,2)`, newFraction(6, 1), nil},
/* 34 */ {`fract(1:2)`, kern.NewFraction(1, 2), nil},
/* 35 */ {`fract(12,2)`, kern.NewFraction(6, 1), nil},
/* 36 */ {`bool(2)`, true, nil},
/* 37 */ {`bool(1:2)`, true, nil},
/* 38 */ {`bool(1.0)`, true, nil},
/* 39 */ {`bool("1")`, true, nil},
/* 40 */ {`bool(false)`, false, nil},
/* 41 */ {`bool([1])`, nil, `bool(): can't convert list to bool`},
/* 42 */ {`dec(false)`, float64(0), nil},
/* 43 */ {`dec(1:2)`, float64(0.5), nil},
/* 44 */ {`dec([1])`, nil, `dec(): can't convert list to float`},
/* 45 */ {`eval("a=3"); a`, int64(3), nil},
/* 41 */ {`bool([1])`, true, nil},
/* 42 */ {`bool([])`, false, nil},
/* 43 */ {`bool({})`, false, nil},
/* 44 */ {`bool({1:"one"})`, true, nil},
/* 45 */ {`dec(false)`, float64(0), nil},
/* 46 */ {`dec(1:2)`, float64(0.5), nil},
/* 47 */ {`dec([1])`, nil, `dec(): can't convert list to float`},
/* 48 */ {`eval("a=3"); a`, int64(3), nil},
/* 49 */ {`int(5:2)`, int64(2), nil},
// /* 45 */ {`string([1])`, nil, `string(): can't convert list to string`},
}
t.Setenv("EXPR_PATH", ".")
// runTestSuiteSpec(t, section, inputs, 45)
// runTestSuiteSpec(t, section, inputs, 49)
runTestSuite(t, section, inputs)
}
+4 -2
View File
@@ -9,6 +9,8 @@ import (
"bytes"
"fmt"
"testing"
"git.portale-stac.it/go-pkg/expr/kern"
)
func TestFuncFmt(t *testing.T) {
@@ -37,11 +39,11 @@ func TestFmt(t *testing.T) {
var b bytes.Buffer
ctx := NewSimpleStore()
currentStdout := SetCtrl(ctx, ControlStdout, &b)
currentStdout := kern.SetCtrl(ctx, kern.ControlStdout, &b)
runCtxTestSuite(t, ctx, section, inputs)
SetCtrl(ctx, ControlStdout, currentStdout)
kern.SetCtrl(ctx, kern.ControlStdout, currentStdout)
if b.String() != text+"\n" {
t.Errorf("println(): Got: %q, Want: %q", b.String(), text+"\n")
}
+3 -2
View File
@@ -21,10 +21,11 @@ func TestFuncRun(t *testing.T) {
/* 7 */ {`builtin "iterator"; run($(1,2,3), func(){1}, "prrr")`, nil, `paramter "vars" must be a dictionary, passed prrr [string]`},
/* 8 */ {`builtin "iterator"; run($(1,2,3), operator=nil)`, nil, nil},
/* 9 */ {`builtin "iterator"; run($(1,2,3), operatorx=nil)`, nil, `run(): unknown param "operatorx"`},
/* 10 */ {`builtin ["os.file", "iterator"]; it = fileReadIterator("test-file.txt"); run(it)`, nil, nil},
}
//t.Setenv("EXPR_PATH", ".")
//runTestSuiteSpec(t, section, inputs, 1)
runTestSuite(t, section, inputs)
runTestSuiteSpec(t, section, inputs, 10)
// runTestSuite(t, section, inputs)
}
+8 -1
View File
@@ -5,6 +5,7 @@
package expr
import (
"io"
"testing"
)
@@ -26,10 +27,16 @@ func TestFuncOs(t *testing.T) {
/* 13 */ {`builtin "os.file"; handle=fileClose(123)`, nil, `fileClose(): invalid file handle`},
/* 14 */ {`builtin "os.file"; handle=fileOpen("/tmp/dummy"); c=fileReadTextAll(handle); fileClose(handle); c`, "bye-bye", nil},
/* 15 */ {`builtin "os.file"; c=fileReadTextAll(123)`, nil, `fileReadTextAll(): invalid file handle 123 [int64]`},
/* 16 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); it++`, "uno", nil},
/* 17 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); it++;it++;it++`, nil, io.EOF.Error()},
/* 18 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); it.clean`, nil, nil},
/* 19 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); string(it)`, `$(fileReadTextIterator@"test-file.txt")`, nil},
/* 20 */ {`builtin "os.file"; handle=fileOpen("/etc/hosts"); fileClose(handle); string(handle)`, `reader`, nil},
/* 21 */ {`builtin "os.file"; handle=fileCreate("/tmp/dummy"); fileClose(handle); string(handle)`, `writer`, nil},
}
// t.Setenv("EXPR_PATH", ".")
//runTestSuiteSpec(t, section, inputs, 2)
// runTestSuiteSpec(t, section, inputs, 19)
runTestSuite(t, section, inputs)
}
+5 -1
View File
@@ -6,6 +6,8 @@ package expr
import (
"testing"
"git.portale-stac.it/go-pkg/expr/kern"
)
func TestFuncString(t *testing.T) {
@@ -28,9 +30,11 @@ func TestFuncString(t *testing.T) {
/* 14 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "789")`, true, nil},
/* 15 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "0125")`, false, nil},
/* 16 */ {`builtin "string"; strEndsWith("0123456789")`, nil, `strEndsWith(): too few params -- expected 2 or more, got 1`},
/* 17 */ {`builtin "string"; strSplit("one-two-three", "-")`, newListA("one", "two", "three"), nil},
/* 17 */ {`builtin "string"; strSplit("one-two-three", "-")`, kern.NewListA("one", "two", "three"), nil},
/* 18 */ {`builtin "string"; strJoin("-", [1, "two", "three"])`, nil, `strJoin(): expected string, got integer (1)`},
/* 19 */ {`builtin "string"; strJoin()`, nil, `strJoin(): too few params -- expected 1 or more, got 0`},
/* 20 */ {`builtin "string"; strUpper("StOp")`, "STOP", nil},
/* 21 */ {`builtin "string"; strLower("StOp")`, "stop", nil},
/* 69 */ /*{`builtin "string"; $$global`, `vars: {
}
+22 -8
View File
@@ -9,6 +9,8 @@ import (
"reflect"
"strings"
"testing"
"git.portale-stac.it/go-pkg/expr/kern"
)
type inputType struct {
@@ -17,7 +19,7 @@ type inputType struct {
wantErr any
}
func runCtxTestSuiteSpec(t *testing.T, ctx ExprContext, section string, inputs []inputType, spec ...int) {
func runCtxTestSuiteSpec(t *testing.T, ctx kern.ExprContext, section string, inputs []inputType, spec ...int) {
succeeded := 0
failed := 0
for _, count := range spec {
@@ -36,7 +38,7 @@ func runTestSuiteSpec(t *testing.T, section string, inputs []inputType, spec ...
runCtxTestSuiteSpec(t, nil, section, inputs, spec...)
}
func runCtxTestSuite(t *testing.T, ctx ExprContext, section string, inputs []inputType) {
func runCtxTestSuite(t *testing.T, ctx kern.ExprContext, section string, inputs []inputType) {
succeeded := 0
failed := 0
@@ -68,10 +70,11 @@ func getWantedError(input *inputType) error {
return wantErr
}
func doTest(t *testing.T, ctx ExprContext, section string, input *inputType, count int) (good bool) {
var expr Expr
func doTest(t *testing.T, ctx kern.ExprContext, section string, input *inputType, count int) (good bool) {
var ast Expr
var gotResult any
var gotErr error
var eq, eqDone bool
wantErr := getWantedError(input)
@@ -86,14 +89,25 @@ func doTest(t *testing.T, ctx ExprContext, section string, input *inputType, cou
scanner := NewScanner(r, DefaultTranslations())
good = true
if expr, gotErr = parser.Parse(scanner); gotErr == nil {
gotResult, gotErr = expr.Eval(ctx)
if ast, gotErr = parser.Parse(scanner); gotErr == nil {
gotResult, gotErr = ast.Eval(ctx)
}
eq := reflect.DeepEqual(gotResult, input.wantResult)
if input.wantResult != nil && gotResult != nil {
if ls1, ok := input.wantResult.(*kern.ListType); ok {
if ls2, ok := gotResult.(*kern.ListType); ok {
eq = ls1.Equals(*ls2)
eqDone = true
}
}
}
if !eqDone {
eq = reflect.DeepEqual(gotResult, input.wantResult)
}
if !eq /*gotResult != input.wantResult*/ {
t.Errorf("%d: `%s` -> result = %v [%s], want = %v [%s]", count, input.source, gotResult, TypeName(gotResult), input.wantResult, TypeName(input.wantResult))
t.Errorf("%d: `%s` -> result = %v [%s], want = %v [%s]", count, input.source, gotResult, kern.TypeName(gotResult), input.wantResult, kern.TypeName(input.wantResult))
good = false
}

Some files were not shown because too many files have changed in this diff Show More