From 79889cd8e17972e03fe8108fe3018b24d1e6963b Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Sun, 14 Jul 2024 16:53:32 +0200 Subject: [PATCH] New builtin module 'iterator' --- builtin-iterator.go | 102 +++++++++++++++++++++++++++++++++++++ common-params.go | 3 +- t_builtin-iterator_test.go | 50 ++++++++++++++++++ t_iterator_test.go | 6 +-- 4 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 builtin-iterator.go create mode 100644 t_builtin-iterator_test.go diff --git a/builtin-iterator.go b/builtin-iterator.go new file mode 100644 index 0000000..b6628a4 --- /dev/null +++ b/builtin-iterator.go @@ -0,0 +1,102 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// builtin-iterator.go +package expr + +import ( + "fmt" + "io" +) + +const ( + iterParamOperator = "operator" + iterParamVars = "vars" +) + +func parseRunArgs(localCtx ExprContext, args []any) (it Iterator, op Functor, err error) { + var ok bool + + if it, ok = args[0].(Iterator); !ok { + err = fmt.Errorf("paramter %q must be an iterator, passed %v [%s]", ParamIterator, args[0], TypeName(args[0])) + return + } + + if len(args) > 1 { + if op, ok = args[1].(Functor); !ok || op == nil { + err = fmt.Errorf("paramter %q must be a function, passed %v [%s]", iterParamOperator, args[1], TypeName(args[1])) + return + } + if len(args) > 2 { + var vars *DictType + if vars, ok = args[2].(*DictType); !ok || vars == nil { + err = fmt.Errorf("paramter %q must be a dictionary, passed %v [%s]", iterParamVars, args[2], TypeName(args[2])) + return + } + for key, value := range *vars { + var varName string + if varName, ok = key.(string); ok { + localCtx.UnsafeSetVar(varName, value) + } + } + } + } + return +} + +func runFunc(ctx ExprContext, name string, args []any) (result any, err error) { + var it Iterator + var ok bool + var op Functor + var v any + var usingDefaultOp = false + var params []any + var item any + + localCtx := ctx.Clone() + localCtx.UnsafeSetVar("it_status", nil) + + 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 = []any{item} + } else { + params = []any{it.Index(), item} + } + + if v, err = op.Invoke(localCtx, iterParamOperator, params); err != nil { + break + } else { + var success bool + if success, ok = ToBool(v); !success || !ok { + break + } + } + } + + if err == io.EOF { + err = nil + } + if err == nil { + result, _ = localCtx.GetVar("it_status") + } + return +} + +func ImportIterFuncs(ctx ExprContext) { + ctx.RegisterFunc("run", NewGolangFunctor(runFunc), TypeAny, []ExprFuncParam{ + NewFuncParam(ParamIterator), + NewFuncParamFlag(iterParamOperator, PfOptional), + NewFuncParamFlag(iterParamVars, PfOptional), + }) +} + +func init() { + RegisterBuiltinModule("iterator", ImportIterFuncs, "Iterator helper functions") +} diff --git a/common-params.go b/common-params.go index bcfe137..8ce5d2b 100644 --- a/common-params.go +++ b/common-params.go @@ -19,9 +19,10 @@ const ( ParamEllipsis = "..." ParamFilepath = "filepath" ParamDirpath = "dirpath" + ParamIterator = "iterator" ) // to be moved in its own source file const ( ConstLastIndex = 0xFFFF_FFFF -) \ No newline at end of file +) diff --git a/t_builtin-iterator_test.go b/t_builtin-iterator_test.go new file mode 100644 index 0000000..2f596c5 --- /dev/null +++ b/t_builtin-iterator_test.go @@ -0,0 +1,50 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// t_builtin-iterator.go +package expr + +import ( + "testing" +) + +func TestFuncRun(t *testing.T) { + section := "Builtin-Iterator" + + inputs := []inputType{ + /* 1 */ {`builtin "iterator"; it=$(1,2,3); run(it)`, nil, nil}, + /* 2 */ {`builtin "iterator"; run($(1,2,3), func(index,item){item+10})`, nil, nil}, + /* 3 */ {`builtin "iterator"; run($(1,2,3), func(index,item){it_status=it_status+item; true}, {"it_status":0})`, int64(6), nil}, + /* 4 */ {`builtin ["iterator", "fmt"]; run($(1,2,3), func(index,item){println(item+10)})`, nil, nil}, + /* 5 */ {`builtin "iterator"; run(nil)`, nil, `paramter "iterator" must be an iterator, passed [nil]`}, + /* 6 */ {`builtin "iterator"; run($(1,2,3), nil)`, nil, `paramter "operator" must be a function, passed [nil]`}, + /* 7 */ {`builtin "iterator"; run($(1,2,3), func(){1}, "prrr")`, nil, `paramter "vars" must be a dictionary, passed prrr [string]`}, + } + + //t.Setenv("EXPR_PATH", ".") + + //runTestSuiteSpec(t, section, inputs, 3) + runTestSuite(t, section, inputs) +} + +// func TestFmt(t *testing.T) { +// section := "Builtin-Fmt" + +// text := "ciao mondo" +// inputs := []inputType{ +// /* 1 */ {fmt.Sprintf(`println("%s")`, text), int64(11), nil}, +// } + +// // t.Setenv("EXPR_PATH", ".") + +// var b bytes.Buffer +// ctx := NewSimpleStore() +// currentStdout := SetCtrl(ctx, ControlStdout, &b) + +// runCtxTestSuite(t, ctx, section, inputs) + +// SetCtrl(ctx, ControlStdout, currentStdout) +// if b.String() != text+"\n" { +// t.Errorf("println(): Got: %q, Want: %q", b.String(), text+"\n") +// } +// } diff --git a/t_iterator_test.go b/t_iterator_test.go index f5dd70b..f1ea0d2 100644 --- a/t_iterator_test.go +++ b/t_iterator_test.go @@ -9,10 +9,10 @@ import "testing" func TestIteratorParser(t *testing.T) { section := "Iterator" inputs := []inputType{ - /* 1 */ {`include "test-resources/iterator.expr"; it=$(ds,3); ()it`, int64(0), nil}, + /* 1 */ {`include "test-resources/iterator.expr"; it=$(ds,3); ^it`, int64(0), nil}, /* 2 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++`, int64(1), nil}, /* 3 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(2), nil}, - /* 4 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; it.reset; ()it`, int64(0), nil}, + /* 4 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; it.reset; ^it`, int64(0), nil}, /* 5 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil}, /* 6 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil}, /* 7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); mul(it)`, int64(12000), nil}, @@ -27,6 +27,6 @@ func TestIteratorParser(t *testing.T) { /* 16 */ {`include "test-resources/filter.expr"; it=$(ds,10); it++`, int64(2), nil}, } - //runTestSuiteSpec(t, section, inputs, 12) + //runTestSuiteSpec(t, section, inputs, 4) runTestSuite(t, section, inputs) }