Compare commits

..

No commits in common. "234759158c6666986838c6baebe4d8be7e23c9bc" and "a02f998fc658e378d3ce920993e7082fa283aa1b" have entirely different histories.

21 changed files with 47 additions and 231 deletions

4
ast.go
View File

@ -19,10 +19,6 @@ 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 {

View File

@ -29,10 +29,6 @@ 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
} }

View File

@ -14,10 +14,6 @@ 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)
} }

View File

@ -133,79 +133,54 @@ 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)) // fmt.Printf("Exiting Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
// exportObjects(dc.ctx, ctx) exportObjects(dc.ctx, ctx)
// // fmt.Printf("Outer-Ctx [%p]: %s\n", dc.ctx, CtxToString(dc.ctx, 0)) // fmt.Printf("Outer-Ctx [%p]: %s\n", dc.ctx, CtxToString(dc.ctx, 0))
// } else { } else {
// err = errInvalidDataSource() 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
}
} }
return return
} }
func (dc *dataCursor) mapItem(mapper Functor, item any) (mappedItem any, err error) {
ctx := cloneContext(dc.ctx) const filterName = "filter"
mappedItem, err = mapper.Invoke(ctx, mapName, []any{item, dc.index}); 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 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 {
filter := dc.ds[filterName] ctx := cloneContext(dc.ctx)
mapper := dc.ds[mapName] // fmt.Printf("Entering Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
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++
if filter != nil { item, err = dc.filter(item)
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()
} }

View File

@ -14,15 +14,8 @@ 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)

View File

@ -6,7 +6,6 @@ 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

View File

@ -6,7 +6,6 @@ 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
} }

View File

@ -19,8 +19,6 @@ const (
currentName = "current" currentName = "current"
indexName = "index" indexName = "index"
countName = "count" countName = "count"
filterName = "filter"
mapName = "map"
) )
type Iterator interface { type Iterator interface {

View File

@ -90,20 +90,16 @@ func (it *ListIterator) TypeName() string {
} }
func (it *ListIterator) HasOperation(name string) bool { func (it *ListIterator) HasOperation(name string) bool {
yes := name == nextName || name == resetName || name == indexName || name == countName || name == currentName yes := name == resetName || name == indexName || name == countName
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:

View File

@ -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: priDefault, priority: priCoalesce,
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: priDefault, priority: priCoalesce,
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: priDefault, priority: priCoalesce,
evalFunc: evalAssignDefault, evalFunc: evalAssignDefault,
} }
} }

View File

@ -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.(*ListType) list, _ := childValue.([]any)
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,9 +47,8 @@ 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
} }

View File

@ -33,6 +33,5 @@ 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)
} }

View File

@ -1,69 +0,0 @@
// 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)
}

View File

@ -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 '[':

View File

@ -132,14 +132,6 @@ 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
@ -171,14 +163,6 @@ 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()

View File

@ -106,7 +106,6 @@ const (
SymKwIn SymKwIn
SymKwInclude SymKwInclude
SymKwNil SymKwNil
SymKwUnset
) )
var keywords map[string]Symbol var keywords map[string]Symbol
@ -124,6 +123,5 @@ func init() {
"NOT": SymKwNot, "NOT": SymKwNot,
"OR": SymKwOr, "OR": SymKwOr,
"NIL": SymKwNil, "NIL": SymKwNil,
"UNSET": SymKwUnset,
} }
} }

View File

@ -30,14 +30,13 @@ 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)
} }

View File

@ -20,11 +20,7 @@ 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 */ {`it=$([1,2,3,4],1); it++`, int64(2), nil}, // /* 12 */ {`include "test-resources/filter.expr"; it=$(ds,10); it++`, int64(1), 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)

View File

@ -1,23 +0,0 @@
// 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)
}

View File

@ -26,7 +26,7 @@ const (
priSign priSign
priFact priFact
priIterValue priIterValue
priDefault priCoalesce
priIncDec priIncDec
priDot priDot
priValue priValue

View File

@ -1,15 +0,0 @@
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)
*/