github.com/MontFerret/ferret@v0.18.0/pkg/runtime/collections/while.go (about)

     1  package collections
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/MontFerret/ferret/pkg/runtime/core"
     7  	"github.com/MontFerret/ferret/pkg/runtime/values"
     8  )
     9  
    10  type (
    11  	WhileMode int
    12  
    13  	WhilePredicate func(ctx context.Context, scope *core.Scope) (bool, error)
    14  
    15  	WhileIterator struct {
    16  		mode      WhileMode
    17  		predicate WhilePredicate
    18  		valVar    string
    19  		pos       int
    20  	}
    21  )
    22  
    23  var (
    24  	WhileModePost WhileMode
    25  	WhileModePre  WhileMode = 1
    26  )
    27  
    28  func NewWhileIterator(
    29  	mode WhileMode,
    30  	valVar string,
    31  	predicate WhilePredicate,
    32  ) (Iterator, error) {
    33  	if valVar == "" {
    34  		return nil, core.Error(core.ErrMissedArgument, "value variable")
    35  	}
    36  
    37  	if predicate == nil {
    38  		return nil, core.Error(core.ErrMissedArgument, "predicate")
    39  	}
    40  
    41  	return &WhileIterator{mode, predicate, valVar, 0}, nil
    42  }
    43  
    44  func NewDefaultWhileIterator(mode WhileMode, predicate WhilePredicate) (Iterator, error) {
    45  	return NewWhileIterator(mode, DefaultValueVar, predicate)
    46  }
    47  
    48  func (iterator *WhileIterator) Next(ctx context.Context, scope *core.Scope) (*core.Scope, error) {
    49  	// if it's Post conditional execution, step in always
    50  	// Otherwise, it's not the first iteration
    51  	if iterator.mode == WhileModePost || iterator.pos > 0 {
    52  		doNext, err := iterator.predicate(ctx, scope)
    53  
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  
    58  		if !doNext {
    59  			return nil, core.ErrNoMoreData
    60  		}
    61  	}
    62  
    63  	counter := values.NewInt(iterator.pos)
    64  	iterator.pos++
    65  
    66  	nextScope := scope.Fork()
    67  
    68  	if err := nextScope.SetVariable(iterator.valVar, counter); err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	return nextScope, nil
    73  }