Compare commits
15 Commits
a02f998fc6
...
234759158c
Author | SHA1 | Date | |
---|---|---|---|
234759158c | |||
00fda29606 | |||
2a2840bdf2 | |||
06373f5126 | |||
e69dad5fb5 | |||
7459057df9 | |||
176969c956 | |||
cde2efacf1 | |||
d7a7b3218c | |||
be3bb12f28 | |||
032916d4fa | |||
f3cc0cc7ad | |||
905337f963 | |||
9a95a837f6 | |||
8547248ea2 |
4
ast.go
4
ast.go
@ -19,6 +19,10 @@ func NewAst() *ast {
|
|||||||
return &ast{}
|
return &ast{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (expr *ast) TypeName() string {
|
||||||
|
return "Expression"
|
||||||
|
}
|
||||||
|
|
||||||
func (expr *ast) ToForest() {
|
func (expr *ast) ToForest() {
|
||||||
if expr.root != nil {
|
if expr.root != nil {
|
||||||
if expr.forest == nil {
|
if expr.forest == nil {
|
||||||
|
@ -29,6 +29,10 @@ func newExprFunctor(e Expr, params []ExprFuncParam, ctx ExprContext) *exprFuncto
|
|||||||
return &exprFunctor{expr: e, params: params, defCtx: defCtx}
|
return &exprFunctor{expr: e, params: params, defCtx: defCtx}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (functor *exprFunctor) TypeName() string {
|
||||||
|
return "ExprFunctor"
|
||||||
|
}
|
||||||
|
|
||||||
func (functor *exprFunctor) GetDefinitionContext() ExprContext {
|
func (functor *exprFunctor) GetDefinitionContext() ExprContext {
|
||||||
return functor.defCtx
|
return functor.defCtx
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,10 @@ func NewGolangFunctor(f FuncTemplate) *golangFunctor {
|
|||||||
return &golangFunctor{f: f}
|
return &golangFunctor{f: f}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (functor *golangFunctor) TypeName() string {
|
||||||
|
return "GoFunctor"
|
||||||
|
}
|
||||||
|
|
||||||
func (functor *golangFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
func (functor *golangFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||||
return functor.f(ctx, name, args)
|
return functor.f(ctx, name, args)
|
||||||
}
|
}
|
||||||
|
@ -133,54 +133,79 @@ func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *dataCursor) _Next() (item any, err error) { // must return io.EOF after the last item
|
// func (dc *dataCursor) _Next() (item any, err error) { // must return io.EOF after the last item
|
||||||
if dc.resource != nil {
|
// if dc.resource != nil {
|
||||||
ctx := cloneContext(dc.ctx)
|
// ctx := cloneContext(dc.ctx)
|
||||||
// fmt.Printf("Entering Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
|
// // fmt.Printf("Entering Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
|
||||||
if item, err = dc.nextFunc.Invoke(ctx, nextName, []any{dc.resource}); err == nil {
|
// if item, err = dc.nextFunc.Invoke(ctx, nextName, []any{dc.resource}); err == nil {
|
||||||
if item == nil {
|
// if item == nil {
|
||||||
err = io.EOF
|
// err = io.EOF
|
||||||
} else {
|
// } else {
|
||||||
dc.index++
|
// dc.index++
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
// // fmt.Printf("Exiting Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
|
||||||
|
// exportObjects(dc.ctx, ctx)
|
||||||
|
// // fmt.Printf("Outer-Ctx [%p]: %s\n", dc.ctx, CtxToString(dc.ctx, 0))
|
||||||
|
// } else {
|
||||||
|
// err = errInvalidDataSource()
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (dc *dataCursor) _filter(item any) (filterdItem any, err error) {
|
||||||
|
// if filter, ok := dc.ds[filterName]; ok {
|
||||||
|
// ctx := cloneContext(dc.ctx)
|
||||||
|
// filterdItem, err = filter.Invoke(ctx, filterName, []any{item, dc.index})
|
||||||
|
// } else {
|
||||||
|
// filterdItem = item
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err error) {
|
||||||
|
var v any
|
||||||
|
var ok bool
|
||||||
|
ctx := cloneContext(dc.ctx)
|
||||||
|
if v, err = filter.Invoke(ctx, filterName, []any{item, dc.index}); 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
|
||||||
}
|
}
|
||||||
// fmt.Printf("Exiting Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
|
|
||||||
exportObjects(dc.ctx, ctx)
|
|
||||||
// fmt.Printf("Outer-Ctx [%p]: %s\n", dc.ctx, CtxToString(dc.ctx, 0))
|
|
||||||
} else {
|
|
||||||
err = errInvalidDataSource()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (dc *dataCursor) mapItem(mapper Functor, item any) (mappedItem any, err error) {
|
||||||
const filterName = "filter"
|
ctx := cloneContext(dc.ctx)
|
||||||
func (dc *dataCursor) filter(item any) (filterdItem any, err error) {
|
mappedItem, err = mapper.Invoke(ctx, mapName, []any{item, dc.index});
|
||||||
if filter, ok := dc.ds[filterName]; ok {
|
|
||||||
ctx := cloneContext(dc.ctx)
|
|
||||||
filterdItem, err = filter.Invoke(ctx, filterName, []any{item, dc.index});
|
|
||||||
} else {
|
|
||||||
filterdItem = item
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *dataCursor) Next() (item any, err error) { // must return io.EOF after the last item
|
func (dc *dataCursor) Next() (item any, err error) { // must return io.EOF after the last item
|
||||||
|
var accepted bool
|
||||||
if dc.resource != nil {
|
if dc.resource != nil {
|
||||||
ctx := cloneContext(dc.ctx)
|
filter := dc.ds[filterName]
|
||||||
// fmt.Printf("Entering Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
|
mapper := dc.ds[mapName]
|
||||||
|
|
||||||
for item == nil && err == nil {
|
for item == nil && err == nil {
|
||||||
|
ctx := cloneContext(dc.ctx)
|
||||||
if item, err = dc.nextFunc.Invoke(ctx, nextName, []any{dc.resource}); err == nil {
|
if item, err = dc.nextFunc.Invoke(ctx, nextName, []any{dc.resource}); err == nil {
|
||||||
if item == nil {
|
if item == nil {
|
||||||
err = io.EOF
|
err = io.EOF
|
||||||
} else {
|
} else {
|
||||||
dc.index++
|
dc.index++
|
||||||
item, err = dc.filter(item)
|
if filter != nil {
|
||||||
|
if accepted, err = dc.checkFilter(filter, item); err != nil || !accepted {
|
||||||
|
item = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if item != nil && mapper != nil {
|
||||||
|
item, err = dc.mapItem(mapper, item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
exportObjects(dc.ctx, ctx)
|
||||||
}
|
}
|
||||||
// fmt.Printf("Exiting Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
|
|
||||||
exportObjects(dc.ctx, ctx)
|
|
||||||
// fmt.Printf("Outer-Ctx [%p]: %s\n", dc.ctx, CtxToString(dc.ctx, 0))
|
|
||||||
} else {
|
} else {
|
||||||
err = errInvalidDataSource()
|
err = errInvalidDataSource()
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,15 @@ type ExprContext interface {
|
|||||||
GetLast() any
|
GetLast() any
|
||||||
SetVar(varName string, value any)
|
SetVar(varName string, value any)
|
||||||
UnsafeSetVar(varName string, value any)
|
UnsafeSetVar(varName string, value any)
|
||||||
|
|
||||||
EnumVars(func(name string) (accept bool)) (varNames []string)
|
EnumVars(func(name string) (accept bool)) (varNames []string)
|
||||||
|
VarCount() int
|
||||||
|
DeleteVar(varName string)
|
||||||
|
|
||||||
EnumFuncs(func(name string) (accept bool)) (funcNames []string)
|
EnumFuncs(func(name string) (accept bool)) (funcNames []string)
|
||||||
|
FuncCount() int
|
||||||
|
DeleteFunc(funcName string)
|
||||||
|
|
||||||
GetFuncInfo(name string) (item ExprFunc, exists bool)
|
GetFuncInfo(name string) (item ExprFunc, exists bool)
|
||||||
Call(name string, args []any) (result any, err error)
|
Call(name string, args []any) (result any, err error)
|
||||||
RegisterFuncInfo(info ExprFunc)
|
RegisterFuncInfo(info ExprFunc)
|
||||||
|
@ -6,6 +6,7 @@ package expr
|
|||||||
|
|
||||||
// ---- Functor interface
|
// ---- Functor interface
|
||||||
type Functor interface {
|
type Functor interface {
|
||||||
|
Typer
|
||||||
Invoke(ctx ExprContext, name string, args []any) (result any, err error)
|
Invoke(ctx ExprContext, name string, args []any) (result any, err error)
|
||||||
SetFunc(info ExprFunc)
|
SetFunc(info ExprFunc)
|
||||||
GetFunc() ExprFunc
|
GetFunc() ExprFunc
|
||||||
|
1
expr.go
1
expr.go
@ -6,6 +6,7 @@ package expr
|
|||||||
|
|
||||||
// ----Expression interface
|
// ----Expression interface
|
||||||
type Expr interface {
|
type Expr interface {
|
||||||
|
Typer
|
||||||
Eval(ctx ExprContext) (result any, err error)
|
Eval(ctx ExprContext) (result any, err error)
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ const (
|
|||||||
currentName = "current"
|
currentName = "current"
|
||||||
indexName = "index"
|
indexName = "index"
|
||||||
countName = "count"
|
countName = "count"
|
||||||
|
filterName = "filter"
|
||||||
|
mapName = "map"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Iterator interface {
|
type Iterator interface {
|
||||||
|
@ -90,16 +90,20 @@ func (it *ListIterator) TypeName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (it *ListIterator) HasOperation(name string) bool {
|
func (it *ListIterator) HasOperation(name string) bool {
|
||||||
yes := name == resetName || name == indexName || name == countName
|
yes := name == nextName || name == resetName || name == indexName || name == countName || name == currentName
|
||||||
return yes
|
return yes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *ListIterator) CallOperation(name string, args []any) (v any, err error) {
|
func (it *ListIterator) CallOperation(name string, args []any) (v any, err error) {
|
||||||
switch name {
|
switch name {
|
||||||
|
case nextName:
|
||||||
|
v, err = it.Next()
|
||||||
case resetName:
|
case resetName:
|
||||||
v, err = it.Reset()
|
v, err = it.Reset()
|
||||||
case indexName:
|
case indexName:
|
||||||
v = int64(it.Index())
|
v = int64(it.Index())
|
||||||
|
case currentName:
|
||||||
|
v, err = it.Current()
|
||||||
case countName:
|
case countName:
|
||||||
v = it.count
|
v = it.count
|
||||||
default:
|
default:
|
||||||
|
@ -11,7 +11,7 @@ func newDefaultTerm(tk *Token) (inst *term) {
|
|||||||
tk: *tk,
|
tk: *tk,
|
||||||
children: make([]*term, 0, 2),
|
children: make([]*term, 0, 2),
|
||||||
position: posInfix,
|
position: posInfix,
|
||||||
priority: priCoalesce,
|
priority: priDefault,
|
||||||
evalFunc: evalDefault,
|
evalFunc: evalDefault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ func newAlternateTerm(tk *Token) (inst *term) {
|
|||||||
tk: *tk,
|
tk: *tk,
|
||||||
children: make([]*term, 0, 2),
|
children: make([]*term, 0, 2),
|
||||||
position: posInfix,
|
position: posInfix,
|
||||||
priority: priCoalesce,
|
priority: priDefault,
|
||||||
evalFunc: evalAlternate,
|
evalFunc: evalAlternate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ func newDefaultAssignTerm(tk *Token) (inst *term) {
|
|||||||
tk: *tk,
|
tk: *tk,
|
||||||
children: make([]*term, 0, 2),
|
children: make([]*term, 0, 2),
|
||||||
position: posInfix,
|
position: posInfix,
|
||||||
priority: priCoalesce,
|
priority: priDefault,
|
||||||
evalFunc: evalAssignDefault,
|
evalFunc: evalAssignDefault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ func evalInclude(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
if IsList(childValue) {
|
if IsList(childValue) {
|
||||||
list, _ := childValue.([]any)
|
list, _ := childValue.(*ListType)
|
||||||
for i, filePathSpec := range list {
|
for i, filePathSpec := range *list {
|
||||||
if filePath, ok := filePathSpec.(string); ok {
|
if filePath, ok := filePathSpec.(string); ok {
|
||||||
if v, err = EvalFile(ctx, filePath); err == nil {
|
if v, err = EvalFile(ctx, filePath); err == nil {
|
||||||
count++
|
count++
|
||||||
@ -47,8 +47,9 @@ func evalInclude(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
} else {
|
} else {
|
||||||
err = opTerm.errIncompatibleType(childValue)
|
err = opTerm.errIncompatibleType(childValue)
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err != nil {
|
||||||
v = count
|
//v = count
|
||||||
|
v = nil
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -33,5 +33,6 @@ func evalIterValue(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
registerTermConstructor(SymOpenClosedRound, newIterValueTerm)
|
// registerTermConstructor(SymOpenClosedRound, newIterValueTerm)
|
||||||
|
registerTermConstructor(SymCaret, newIterValueTerm)
|
||||||
}
|
}
|
||||||
|
69
operator-unset.go
Normal file
69
operator-unset.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-unset.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
//-------- unset term
|
||||||
|
|
||||||
|
func newUnsetTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 1),
|
||||||
|
position: posPrefix,
|
||||||
|
priority: priSign,
|
||||||
|
evalFunc: evalUnset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteContextItem(ctx ExprContext, opTerm *term, item any) (deleted bool, err error) {
|
||||||
|
if name, ok := item.(string); ok {
|
||||||
|
var size int
|
||||||
|
if strings.HasSuffix(name, "()") {
|
||||||
|
size = ctx.FuncCount()
|
||||||
|
ctx.DeleteFunc(strings.TrimRight(name, "()"))
|
||||||
|
deleted = ctx.FuncCount() < size
|
||||||
|
} else {
|
||||||
|
size = ctx.VarCount()
|
||||||
|
ctx.DeleteVar(name)
|
||||||
|
deleted = ctx.VarCount() < size
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = opTerm.errIncompatibleType(item)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalUnset(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||||
|
var childValue any
|
||||||
|
var deleted bool
|
||||||
|
|
||||||
|
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
if IsList(childValue) {
|
||||||
|
list, _ := childValue.(*ListType)
|
||||||
|
for _, item := range *list {
|
||||||
|
if deleted, err = deleteContextItem(ctx, opTerm, item); err != nil {
|
||||||
|
break
|
||||||
|
} else if deleted {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if deleted, err = deleteContextItem(ctx, opTerm, childValue); err == nil && deleted {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
v = int64(count)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
registerTermConstructor(SymKwUnset, newUnsetTerm)
|
||||||
|
}
|
@ -269,11 +269,11 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
|
|||||||
tk = scanner.makeToken(SymDollar, ch)
|
tk = scanner.makeToken(SymDollar, ch)
|
||||||
}
|
}
|
||||||
case '(':
|
case '(':
|
||||||
if next, _ := scanner.peek(); next == ')' {
|
// if next, _ := scanner.peek(); next == ')' {
|
||||||
tk = scanner.moveOn(SymOpenClosedRound, ch, next)
|
// tk = scanner.moveOn(SymOpenClosedRound, ch, next)
|
||||||
} else {
|
// } else {
|
||||||
tk = scanner.makeToken(SymOpenRound, ch)
|
tk = scanner.makeToken(SymOpenRound, ch)
|
||||||
}
|
// }
|
||||||
case ')':
|
case ')':
|
||||||
tk = scanner.makeToken(SymClosedRound, ch)
|
tk = scanner.makeToken(SymClosedRound, ch)
|
||||||
case '[':
|
case '[':
|
||||||
|
@ -132,6 +132,14 @@ func (ctx *SimpleStore) EnumVars(acceptor func(name string) (accept bool)) (varN
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *SimpleStore) VarCount() int {
|
||||||
|
return len(ctx.varStore)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *SimpleStore) DeleteVar(varName string) {
|
||||||
|
delete(ctx.varStore, varName)
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *SimpleStore) GetFuncInfo(name string) (info ExprFunc, exists bool) {
|
func (ctx *SimpleStore) GetFuncInfo(name string) (info ExprFunc, exists bool) {
|
||||||
info, exists = ctx.funcStore[name]
|
info, exists = ctx.funcStore[name]
|
||||||
return
|
return
|
||||||
@ -163,6 +171,14 @@ func (ctx *SimpleStore) EnumFuncs(acceptor func(name string) (accept bool)) (fun
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *SimpleStore) FuncCount() int {
|
||||||
|
return len(ctx.funcStore)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *SimpleStore) DeleteFunc(funcName string) {
|
||||||
|
delete(ctx.funcStore, funcName)
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *SimpleStore) Call(name string, args []any) (result any, err error) {
|
func (ctx *SimpleStore) Call(name string, args []any) (result any, err error) {
|
||||||
if info, exists := GetLocalFuncInfo(ctx, name); exists {
|
if info, exists := GetLocalFuncInfo(ctx, name); exists {
|
||||||
functor := info.Functor()
|
functor := info.Functor()
|
||||||
|
@ -106,6 +106,7 @@ const (
|
|||||||
SymKwIn
|
SymKwIn
|
||||||
SymKwInclude
|
SymKwInclude
|
||||||
SymKwNil
|
SymKwNil
|
||||||
|
SymKwUnset
|
||||||
)
|
)
|
||||||
|
|
||||||
var keywords map[string]Symbol
|
var keywords map[string]Symbol
|
||||||
@ -123,5 +124,6 @@ func init() {
|
|||||||
"NOT": SymKwNot,
|
"NOT": SymKwNot,
|
||||||
"OR": SymKwOr,
|
"OR": SymKwOr,
|
||||||
"NIL": SymKwNil,
|
"NIL": SymKwNil,
|
||||||
|
"UNSET": SymKwUnset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,14 @@ func TestFuncs(t *testing.T) {
|
|||||||
/* 17 */ {`f=func(x,n){1}; f(3,4,)`, nil, `[1:24] expected "function-param-value", got ")"`},
|
/* 17 */ {`f=func(x,n){1}; f(3,4,)`, nil, `[1:24] expected "function-param-value", got ")"`},
|
||||||
/* 18 */ {`factory=func(base){func(){@base=base+1}}; inc10=factory(10); inc5=factory(5); inc10(); inc5(); inc10()`, int64(12), nil},
|
/* 18 */ {`factory=func(base){func(){@base=base+1}}; inc10=factory(10); inc5=factory(5); inc10(); inc5(); inc10()`, int64(12), nil},
|
||||||
/* 19 */ {`f=func(a,y=1,z="sos"){}; string(f)`, `f(a, y=1, z="sos"):any{}`, nil},
|
/* 19 */ {`f=func(a,y=1,z="sos"){}; string(f)`, `f(a, y=1, z="sos"):any{}`, nil},
|
||||||
|
// /* 20 */ {`a=[func(){3}]; a[0]()`, int64(3), nil},
|
||||||
// /* 20 */ {`m={}; m["f"]=func(){3}; m["f"]()`, int64(3), nil},
|
// /* 20 */ {`m={}; m["f"]=func(){3}; m["f"]()`, int64(3), nil},
|
||||||
// /* 18 */ {`f=func(a){a*2}`, nil, errors.New(`[1:24] expected "function-param-value", got ")"`)},
|
// /* 18 */ {`f=func(a){a*2}`, nil, errors.New(`[1:24] expected "function-param-value", got ")"`)},
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 20)
|
//runTestSuiteSpec(t, section, inputs, 20)
|
||||||
runTestSuite(t, section, inputs)
|
runTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,11 @@ func TestIteratorParser(t *testing.T) {
|
|||||||
/* 9 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it.clean`, true, nil},
|
/* 9 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it.clean`, true, nil},
|
||||||
/* 10 */ {`it=$(1,2,3); it++`, int64(1), nil},
|
/* 10 */ {`it=$(1,2,3); it++`, int64(1), nil},
|
||||||
/* 11 */ {`it=$(1,2,3); it++; it.reset; it++`, int64(1), nil},
|
/* 11 */ {`it=$(1,2,3); it++; it.reset; it++`, int64(1), nil},
|
||||||
// /* 12 */ {`include "test-resources/filter.expr"; it=$(ds,10); it++`, int64(1), nil},
|
/* 12 */ {`it=$([1,2,3,4],1); it++`, int64(2), nil},
|
||||||
|
/* 13 */ {`it=$([1,2,3,4],1,3); it++; it++;`, int64(3), nil},
|
||||||
|
/* 14 */ {`it=$([1,2,3,4],1,3,2); it++; it++;`, int64(4), nil},
|
||||||
|
/* 15 */ {`it=$([1,2,3,4],1,2,2); it++; it++;`, nil, `EOF`},
|
||||||
|
/* 16 */ {`include "test-resources/filter.expr"; it=$(ds,10); it++`, int64(2), nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
//runTestSuiteSpec(t, section, inputs, 12)
|
//runTestSuiteSpec(t, section, inputs, 12)
|
||||||
|
23
t_operator_test.go
Normal file
23
t_operator_test.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// t_operator_test.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOperator(t *testing.T) {
|
||||||
|
section := "Operator"
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {`a=1; unset "a"; a`, nil, `undefined variable or function "a"`},
|
||||||
|
/* 2 */ {`a=1; unset ["a", "b"]`, int64(1), nil},
|
||||||
|
/* 3 */ {`f=func(){3}; unset "f()"`, int64(1), nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
|
//runTestSuiteSpec(t, section, inputs, 3)
|
||||||
|
runTestSuite(t, section, inputs)
|
||||||
|
}
|
2
term.go
2
term.go
@ -26,7 +26,7 @@ const (
|
|||||||
priSign
|
priSign
|
||||||
priFact
|
priFact
|
||||||
priIterValue
|
priIterValue
|
||||||
priCoalesce
|
priDefault
|
||||||
priIncDec
|
priIncDec
|
||||||
priDot
|
priDot
|
||||||
priValue
|
priValue
|
||||||
|
15
test-resources/filter.expr
Normal file
15
test-resources/filter.expr
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
ds={
|
||||||
|
"init":func(end){@end=end; @current=0 but true},
|
||||||
|
"current":func(){current},
|
||||||
|
"next":func(){
|
||||||
|
((next=current+1) <= end) ? [true] {@current=next but current} :: {nil}
|
||||||
|
}
|
||||||
|
, "filter":func(item,index) { item > 0 }
|
||||||
|
, "map": func(item,index) { item * 2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example
|
||||||
|
;
|
||||||
|
it=$(ds,3);
|
||||||
|
add(it)
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user