merged with datasource-context
This commit is contained in:
commit
723976b37e
@ -11,6 +11,20 @@ func cloneContext(sourceCtx ExprContext) (clonedCtx ExprContext) {
|
||||
return
|
||||
}
|
||||
|
||||
func exportVar(ctx ExprContext, name string, value any) {
|
||||
if name[0] == '@' {
|
||||
name = name[1:]
|
||||
}
|
||||
ctx.setVar(name, value)
|
||||
}
|
||||
|
||||
func exportFunc(ctx ExprContext, name string, info ExprFunc) {
|
||||
if name[0] == '@' {
|
||||
name = name[1:]
|
||||
}
|
||||
ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
|
||||
}
|
||||
|
||||
func exportObjects(destCtx, sourceCtx ExprContext) {
|
||||
exportAll := isEnabled(sourceCtx, control_export_all)
|
||||
// Export variables
|
||||
@ -24,5 +38,4 @@ func exportObjects(destCtx, sourceCtx ExprContext) {
|
||||
exportFunc(destCtx, refName, info)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,25 +23,37 @@ type dataCursor struct {
|
||||
currentFunc Functor
|
||||
}
|
||||
|
||||
func newDataCursor(ctx ExprContext) (dc *dataCursor) {
|
||||
dc = &dataCursor{
|
||||
index: -1,
|
||||
ctx: ctx.Clone(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (dc *dataCursor) String() string {
|
||||
return "$(...)"
|
||||
}
|
||||
|
||||
func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
|
||||
if item, err = dc.currentFunc.Invoke(dc.ctx, currentName, []any{}); err == nil && item == nil {
|
||||
ctx := cloneContext(dc.ctx)
|
||||
if item, err = dc.currentFunc.Invoke(ctx, currentName, []any{}); err == nil && item == nil {
|
||||
err = io.EOF
|
||||
}
|
||||
exportObjects(dc.ctx, ctx)
|
||||
return
|
||||
}
|
||||
|
||||
func (dc *dataCursor) Next() (item any, err error) { // must return io.EOF after the last item
|
||||
if item, err = dc.nextFunc.Invoke(dc.ctx, nextName, []any{}); err == nil {
|
||||
ctx := cloneContext(dc.ctx)
|
||||
if item, err = dc.nextFunc.Invoke(ctx, nextName, []any{}); err == nil {
|
||||
if item == nil {
|
||||
err = io.EOF
|
||||
} else {
|
||||
dc.index++
|
||||
}
|
||||
}
|
||||
exportObjects(dc.ctx, ctx)
|
||||
return
|
||||
}
|
||||
|
||||
|
19
expr_test.go
19
expr_test.go
@ -27,11 +27,22 @@ func TestExpr(t *testing.T) {
|
||||
succeeded := 0
|
||||
failed := 0
|
||||
|
||||
// inputs1 := []inputType{
|
||||
// /* 1 */ {`0?{}`, nil, nil},
|
||||
// }
|
||||
inputs1 := []inputType{
|
||||
/* 1 */ {`
|
||||
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}
|
||||
}
|
||||
};
|
||||
it=$(ds,3);
|
||||
it++;
|
||||
it++
|
||||
`, int64(1), nil},
|
||||
}
|
||||
|
||||
for i, input := range inputs {
|
||||
for i, input := range inputs1 {
|
||||
var expr Expr
|
||||
var gotResult any
|
||||
var gotErr error
|
||||
|
@ -27,8 +27,3 @@ func evalExpr(ctx ExprContext, self *term) (v any, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// init
|
||||
// func init() {
|
||||
// registerTermConstructor(SymExpression, newExprTerm)
|
||||
// }
|
||||
|
@ -40,20 +40,6 @@ func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func exportVar(ctx ExprContext, name string, value any) {
|
||||
if name[0] == '@' {
|
||||
name = name[1:]
|
||||
}
|
||||
ctx.setVar(name, value)
|
||||
}
|
||||
|
||||
func exportFunc(ctx ExprContext, name string, info ExprFunc) {
|
||||
if name[0] == '@' {
|
||||
name = name[1:]
|
||||
}
|
||||
ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
|
||||
}
|
||||
|
||||
// -------- function definition term
|
||||
func newFuncDefTerm(tk *Token, args []*term) *term {
|
||||
return &term{
|
||||
|
@ -77,10 +77,7 @@ func evalIterator(ctx ExprContext, self *term) (v any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
dc := &dataCursor{
|
||||
index: -1,
|
||||
ctx: ctx.Clone(),
|
||||
}
|
||||
dc := newDataCursor(ctx)
|
||||
|
||||
if initFunc, exists := ds[initName]; exists && initFunc != nil {
|
||||
var args []any
|
||||
@ -91,9 +88,12 @@ func evalIterator(ctx ExprContext, self *term) (v any, err error) {
|
||||
} else {
|
||||
args = []any{}
|
||||
}
|
||||
if dc.resource, err = initFunc.Invoke(dc.ctx, initName, args); err != nil {
|
||||
|
||||
initCtx := dc.ctx.Clone()
|
||||
if dc.resource, err = initFunc.Invoke(initCtx, initName, args); err != nil {
|
||||
return
|
||||
}
|
||||
exportObjects(dc.ctx, initCtx)
|
||||
}
|
||||
|
||||
dc.nextFunc, _ = ds[nextName]
|
||||
|
49
operator-context.go
Normal file
49
operator-context.go
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// operator-context-value.go
|
||||
package expr
|
||||
|
||||
//-------- context term
|
||||
|
||||
func newContextTerm(tk *Token) (inst *term) {
|
||||
return &term{
|
||||
tk: *tk,
|
||||
children: make([]*term, 0, 1),
|
||||
position: posPrefix,
|
||||
priority: priPrePost,
|
||||
evalFunc: evalContextValue,
|
||||
}
|
||||
}
|
||||
|
||||
func evalContextValue(ctx ExprContext, self *term) (v any, err error) {
|
||||
var childValue any
|
||||
|
||||
var sourceCtx ExprContext
|
||||
if len(self.children) == 0 {
|
||||
sourceCtx = ctx
|
||||
} else if childValue, err = self.evalPrefix(ctx); err == nil {
|
||||
if dc, ok := childValue.(*dataCursor); ok {
|
||||
sourceCtx = dc.ctx
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
if sourceCtx != nil {
|
||||
keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
|
||||
d := make(map[string]any)
|
||||
for _, key := range keys {
|
||||
d[key], _ = sourceCtx.GetVar(key)
|
||||
}
|
||||
v = d
|
||||
} else {
|
||||
err = self.errIncompatibleType(childValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// init
|
||||
func init() {
|
||||
registerTermConstructor(SymDoubleDollar, newContextTerm)
|
||||
}
|
@ -4,65 +4,7 @@
|
||||
// operator-selector.go
|
||||
package expr
|
||||
|
||||
// //-------- export all term
|
||||
|
||||
// func newSelectorTerm(tk *Token) (inst *term) {
|
||||
// return &term{
|
||||
// tk: *tk,
|
||||
// children: make([]*term, 0, 3),
|
||||
// position: posMultifix,
|
||||
// priority: priSelector,
|
||||
// evalFunc: evalSelector,
|
||||
// }
|
||||
// }
|
||||
|
||||
// func isSelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (selectedValue any, err error) {
|
||||
// caseData, _ := caseSel.(*selectorCase)
|
||||
// if caseData.filterList == nil {
|
||||
// selectedValue, err = caseData.caseExpr.eval(ctx, false)
|
||||
// } else {
|
||||
// filterList := caseData.filterList.children
|
||||
// if len(filterList) == 0 && exprValue == int64(caseIndex) {
|
||||
// selectedValue, err = caseData.caseExpr.eval(ctx, false)
|
||||
// } else {
|
||||
// var caseValue any
|
||||
// for _, caseTerm := range filterList {
|
||||
// if caseValue, err = caseTerm.compute(ctx); err != nil || caseValue == exprValue {
|
||||
// selectedValue, err = caseData.caseExpr.eval(ctx, false)
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// func evalSelector(ctx ExprContext, self *term) (v any, err error) {
|
||||
// var exprValue any
|
||||
// // var caseList []*term
|
||||
|
||||
// if err = self.checkOperands(); err != nil {
|
||||
// return
|
||||
// }
|
||||
// exprTerm := self.children[0]
|
||||
// if exprValue, err = exprTerm.compute(ctx); err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
// caseList := self.children[1:]
|
||||
// for i, caseTerm := range caseList {
|
||||
// caseSel := caseTerm.value()
|
||||
// if v, err = isSelectorCase(ctx, exprValue, caseSel, i); err != nil || v != nil {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// if err == nil && v == nil {
|
||||
// err = exprTerm.tk.Errorf("no case catches the value (%v) of the selection expression", exprValue)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
//-------- export all term
|
||||
//-------- selector term
|
||||
|
||||
func newSelectorTerm(tk *Token) (inst *term) {
|
||||
return &term{
|
||||
@ -74,7 +16,7 @@ func newSelectorTerm(tk *Token) (inst *term) {
|
||||
}
|
||||
}
|
||||
|
||||
func isSelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (match bool, selectedValue any, err error) {
|
||||
func trySelectorCase(ctx 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, false)
|
||||
@ -113,7 +55,7 @@ func evalSelector(ctx ExprContext, self *term) (v any, err error) {
|
||||
caseList, _ := caseListTerm.value().([]*term)
|
||||
for i, caseTerm := range caseList {
|
||||
caseSel := caseTerm.value()
|
||||
if match, v, err = isSelectorCase(ctx, exprValue, caseSel, i); err != nil || match {
|
||||
if match, v, err = trySelectorCase(ctx, exprValue, caseSel, i); err != nil || match {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -242,6 +242,8 @@ func (self *scanner) fetchNextToken() (tk *Token) {
|
||||
if next, _ := self.peek(); next == '(' {
|
||||
tk = self.moveOn(SymDollarRound, ch, next)
|
||||
tk.source += ")"
|
||||
} else if next == '$' {
|
||||
tk = self.moveOn(SymDoubleDollar, ch, next)
|
||||
} else {
|
||||
tk = self.makeToken(SymDollar, ch)
|
||||
}
|
||||
@ -249,8 +251,8 @@ func (self *scanner) fetchNextToken() (tk *Token) {
|
||||
if next, _ := self.peek(); next == ')' {
|
||||
tk = self.moveOn(SymOpenClosedRound, ch, next)
|
||||
} else {
|
||||
tk = self.makeToken(SymOpenRound, ch)
|
||||
}
|
||||
tk = self.makeToken(SymOpenRound, ch)
|
||||
}
|
||||
case ')':
|
||||
tk = self.makeToken(SymClosedRound, ch)
|
||||
case '[':
|
||||
|
Loading…
Reference in New Issue
Block a user