diff --git a/operand-iterator.go b/operand-iterator.go index e075200..1a9c22b 100644 --- a/operand-iterator.go +++ b/operand-iterator.go @@ -12,7 +12,7 @@ import ( // -------- iterator term -func newIteratorTerm(tk *Token, dsTerm *term, args []*term) *term { +func newDsIteratorTerm(tk *Token, dsTerm *term, args []*term) *term { tk.Sym = SymIterator children := make([]*term, 0, 1+len(args)) @@ -28,6 +28,18 @@ func newIteratorTerm(tk *Token, dsTerm *term, args []*term) *term { } } +func newIteratorTerm(tk *Token, args []*term) *term { + tk.Sym = SymIterator + return &term{ + tk: *tk, + parent: nil, + children: args, + position: posLeaf, + priority: priValue, + evalFunc: evalIterator, + } +} + // -------- eval iterator func evalTermArray(ctx ExprContext, a []*term) (values []any, err error) { @@ -43,59 +55,21 @@ func evalTermArray(ctx ExprContext, a []*term) (values []any, err error) { return } -// func getDataSourceDict(ctx ExprContext, self *term) (ds map[string]Functor, err error) { -// var value any -// if len(self.children) < 1 || self.children[0] == nil { -// err = self.Errorf("missing the data-source parameter") -// return -// } - -// if value, err = self.children[0].compute(ctx); err != nil { -// return -// } - -// if dictAny, ok := value.(map[any]any); ok { -// ds = make(map[string]Functor) -// // required functions -// for _, k := range []string{currentName, nextName} { -// if item, exists := dictAny[k]; exists && item != nil { -// if functor, ok := item.(*funcDefFunctor); ok { -// ds[k] = functor -// } -// } else { -// err = fmt.Errorf("the data-source must provide a non-nil %q operator", k) -// return -// } -// } -// // Optional functions -// for _, k := range []string{initName, resetName, cleanName} { -// if item, exists := dictAny[k]; exists && item != nil { -// if functor, ok := item.(*funcDefFunctor); ok { -// ds[k] = functor -// } -// } -// } -// } else { -// err = self.Errorf("the first param (data-source) of an iterator must be a dict, not a %T", value) -// } -// return -// } - -func getDataSourceDict(ctx ExprContext, self *term) (ds map[string]Functor, err error) { - var value any +func evalFirstChild(ctx ExprContext, self *term) (value any, err error) { if len(self.children) < 1 || self.children[0] == nil { err = self.Errorf("missing the data-source parameter") return } - if value, err = self.children[0].compute(ctx); err != nil { - return - } + value, err = self.children[0].compute(ctx) + return +} - requiredFields := []string{currentName, nextName} - fieldsMask := 0b11 - foundFields := 0 - if dictAny, ok := value.(map[any]any); ok { +func getDataSourceDict(ctx ExprContext, self *term, firstChildValue any) (ds map[string]Functor, err error) { + if dictAny, ok := firstChildValue.(map[any]any); ok { + requiredFields := []string{currentName, nextName} + fieldsMask := 0b11 + foundFields := 0 ds = make(map[string]Functor) for keyAny, item := range dictAny { if key, ok := keyAny.(string); ok { @@ -117,45 +91,73 @@ func getDataSourceDict(ctx ExprContext, self *term) (ds map[string]Functor, err } err = fmt.Errorf("the data-source must provide a non-nil %q operator(s)", strings.Join(missingFields, ", ")) } - } else { - err = self.Errorf("the first param (data-source) of an iterator must be a dict, not a %T", value) + // } else { + // err = self.Errorf("the first param (data-source) of an iterator must be a dict, not a %T", value) } return } func evalIterator(ctx ExprContext, self *term) (v any, err error) { + var firstChildValue any var ds map[string]Functor - if ds, err = getDataSourceDict(ctx, self); err != nil { + if firstChildValue, err = evalFirstChild(ctx, self); err != nil { return } - dc := newDataCursor(ctx, ds) - // var it Iterator = dc - // fmt.Println(it) - if initFunc, exists := ds[initName]; exists && initFunc != nil { - var args []any - if len(self.children) > 1 { - if args, err = evalTermArray(ctx, self.children[1:]); err != nil { - return - } - } else { - args = []any{} - } - - initCtx := dc.ctx.Clone() - if dc.resource, err = initFunc.Invoke(initCtx, initName, args); err != nil { - return - } - exportObjects(dc.ctx, initCtx) + if ds, err = getDataSourceDict(ctx, self, firstChildValue); err != nil { + return } - dc.nextFunc, _ = ds[nextName] - dc.currentFunc, _ = ds[currentName] - dc.cleanFunc, _ = ds[cleanName] - dc.resetFunc, _ = ds[resetName] + if ds != nil { + dc := newDataCursor(ctx, ds) + if initFunc, exists := ds[initName]; exists && initFunc != nil { + var args []any + if len(self.children) > 1 { + if args, err = evalTermArray(ctx, self.children[1:]); err != nil { + return + } + } else { + args = []any{} + } - v = dc + initCtx := dc.ctx.Clone() + if dc.resource, err = initFunc.Invoke(initCtx, initName, args); err != nil { + return + } + exportObjects(dc.ctx, initCtx) + } + dc.nextFunc, _ = ds[nextName] + dc.currentFunc, _ = ds[currentName] + dc.cleanFunc, _ = ds[cleanName] + dc.resetFunc, _ = ds[resetName] + + v = dc + } else if list, ok := firstChildValue.(*ListType); ok { + v = NewListIterator(list) + } else { + var list *ListType + if list, err = evalChildren(ctx, self.children, firstChildValue); err == nil { + v = NewListIterator(list) + } + } + return +} + +func evalChildren(ctx ExprContext, terms []*term, firstChildValue any) (list *ListType, err error) { + items := make(ListType, len(terms)) + for i, tree := range terms { + var param any + if i == 0 && firstChildValue != nil { + param = firstChildValue + } else if param, err = tree.compute(ctx); err != nil { + break + } + items[i] = param + } + if err == nil { + list = &items + } return } diff --git a/parser.go b/parser.go index 7c323fb..0097d4e 100644 --- a/parser.go +++ b/parser.go @@ -58,42 +58,6 @@ func (self *parser) parseFuncCall(scanner *scanner, allowVarRef bool, tk *Token) return } -// func (self *parser) parseFuncDef(scanner *scanner) (tree *term, err error) { -// // Example: "add = func(x,y) {x+y} -// var body *ast -// args := make([]*term, 0) -// tk := scanner.Next() -// for tk.Sym != SymClosedRound && tk.Sym != SymEos { -// if tk.Sym == SymIdentifier { -// t := newTerm(tk, nil) -// args = append(args, t) -// } else { -// err = tk.Errorf("invalid param %q, variable identifier expected", tk.source) -// break -// } -// tk = scanner.Next() -// } -// if err == nil && tk.Sym != SymClosedRound { -// err = tk.Errorf("unterminate function params list") -// } -// if err == nil { -// tk = scanner.Next() -// if tk.Sym == SymOpenBrace { -// body, err = self.parseGeneral(scanner, true, true, SymClosedBrace) -// } -// } -// if err == nil { -// // TODO Check arguments -// if scanner.Previous().Sym != SymClosedBrace { -// err = scanner.Previous().Errorf("not properly terminated function body") -// } else { -// tk = scanner.makeValueToken(SymExpression, "", body) -// tree = newFuncDefTerm(tk, args) -// } -// } -// return -// } - func (self *parser) parseFuncDef(scanner *scanner) (tree *term, err error) { // Example: "add = func(x,y) {x+y} var body *ast @@ -175,26 +139,26 @@ func (self *parser) parseList(scanner *scanner, allowVarRef bool) (subtree *term } func (self *parser) parseIterDef(scanner *scanner, allowVarRef bool) (subtree *term, err error) { - var ds *term + // var ds *term tk := scanner.Previous() args := make([]*term, 0) lastSym := SymUnknown - dsExpected := true + //dsExpected := true itemExpected := false for lastSym != SymClosedRound && lastSym != SymEos { var subTree *ast if subTree, err = self.parseItem(scanner, allowVarRef, SymComma, SymClosedRound); err == nil { if subTree.root != nil { - if dsExpected { - if sym := subTree.root.symbol(); sym == SymDict || sym == SymIdentifier { - ds = subTree.root - } else { - err = subTree.root.Errorf("data-source dictionary expected, got %q", subTree.root.source()) - } - dsExpected = false - } else { - args = append(args, subTree.root) - } + /* if dsExpected { + if sym := subTree.root.symbol(); sym == SymDict || sym == SymIdentifier { + ds = subTree.root + } else { + err = subTree.root.Errorf("data-source dictionary expected, got %q", subTree.root.source()) + } + dsExpected = false + } else {*/ + args = append(args, subTree.root) + // } } else if itemExpected { prev := scanner.Previous() err = prev.Errorf("expected iterator argument, got %q", prev) @@ -210,10 +174,8 @@ func (self *parser) parseIterDef(scanner *scanner, allowVarRef bool) (subtree *t // TODO Check arguments if lastSym != SymClosedRound { err = scanner.Previous().Errorf("unterminate iterator param list") - } else if ds != nil { - subtree = newIteratorTerm(tk, ds, args) } else { - tk.Errorf("missing data-source param") + subtree = newIteratorTerm(tk, args) } } return