Pass context through operators

Allows more sophisticated functionality
This commit is contained in:
Mike Farah
2021-02-11 10:58:40 +11:00
parent 3bae44be68
commit c6efd5519b
40 changed files with 439 additions and 434 deletions
+62 -9
View File
@@ -7,7 +7,7 @@ import (
"gopkg.in/yaml.v3"
)
type operatorHandler func(d *dataTreeNavigator, matchingNodes *list.List, expressionNode *ExpressionNode) (*list.List, error)
type operatorHandler func(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error)
func unwrapDoc(node *yaml.Node) *yaml.Node {
if node.Kind == yaml.DocumentNode {
@@ -16,8 +16,67 @@ func unwrapDoc(node *yaml.Node) *yaml.Node {
return node
}
func emptyOperator(d *dataTreeNavigator, matchingNodes *list.List, expressionNode *ExpressionNode) (*list.List, error) {
return list.New(), nil
func emptyOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
context.MatchingNodes = list.New()
return context, nil
}
type crossFunctionCalculation func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error)
func doCrossFunc(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode, calculation crossFunctionCalculation) (Context, error) {
var results = list.New()
lhs, err := d.GetMatchingNodes(context, expressionNode.Lhs)
if err != nil {
return Context{}, err
}
log.Debugf("crossFunction LHS len: %v", lhs.MatchingNodes.Len())
rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs)
if err != nil {
return Context{}, err
}
for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() {
lhsCandidate := el.Value.(*CandidateNode)
for rightEl := rhs.MatchingNodes.Front(); rightEl != nil; rightEl = rightEl.Next() {
log.Debugf("Applying calc")
rhsCandidate := rightEl.Value.(*CandidateNode)
resultCandidate, err := calculation(d, context, lhsCandidate, rhsCandidate)
if err != nil {
return Context{}, err
}
results.PushBack(resultCandidate)
}
}
return context.ChildContext(results), nil
}
func crossFunction(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode, calculation crossFunctionCalculation) (Context, error) {
var results = list.New()
var evaluateAllTogether = true
for matchEl := context.MatchingNodes.Front(); matchEl != nil; matchEl = matchEl.Next() {
evaluateAllTogether = evaluateAllTogether && matchEl.Value.(*CandidateNode).EvaluateTogether
if !evaluateAllTogether {
break
}
}
if evaluateAllTogether {
return doCrossFunc(d, context, expressionNode, calculation)
}
for matchEl := context.MatchingNodes.Front(); matchEl != nil; matchEl = matchEl.Next() {
innerResults, err := doCrossFunc(d, context.SingleChildContext(matchEl.Value.(*CandidateNode)), expressionNode, calculation)
if err != nil {
return Context{}, err
}
results.PushBackList(innerResults.MatchingNodes)
}
return context.ChildContext(results), nil
}
func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode {
@@ -29,12 +88,6 @@ func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode {
return owner.CreateChild(nil, node)
}
func nodeToMap(candidate *CandidateNode) *list.List {
elMap := list.New()
elMap.PushBack(candidate)
return elMap
}
func createTraversalTree(path []interface{}, traversePrefs traversePreferences) *ExpressionNode {
if len(path) == 0 {
return &ExpressionNode{Operation: &Operation{OperationType: selfReferenceOpType}}