yq/pkg/yqlib/operator_create_map.go
Mike Farah 13d1bbb45f
Generic ast (#1829)
Remove dependency on yaml.Node for internal AST representation. Yaml decoder is now just another decoder.
2023-10-18 12:11:53 +11:00

92 lines
2.6 KiB
Go

package yqlib
import (
"container/list"
)
func createMapOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("-- createMapOperation")
//each matchingNodes entry should turn into a sequence of keys to create.
//then collect object should do a cross function of the same index sequence for all matches.
sequences := list.New()
if context.MatchingNodes.Len() > 0 {
for matchingNodeEl := context.MatchingNodes.Front(); matchingNodeEl != nil; matchingNodeEl = matchingNodeEl.Next() {
matchingNode := matchingNodeEl.Value.(*CandidateNode)
sequenceNode, err := sequenceFor(d, context, matchingNode, expressionNode)
if err != nil {
return Context{}, err
}
sequences.PushBack(sequenceNode)
}
} else {
sequenceNode, err := sequenceFor(d, context, nil, expressionNode)
if err != nil {
return Context{}, err
}
sequences.PushBack(sequenceNode)
}
node := listToNodeSeq(sequences)
return context.SingleChildContext(node), nil
}
func sequenceFor(d *dataTreeNavigator, context Context, matchingNode *CandidateNode, expressionNode *ExpressionNode) (*CandidateNode, error) {
var document uint
var filename string
var fileIndex int
var matches = list.New()
if matchingNode != nil {
document = matchingNode.GetDocument()
filename = matchingNode.GetFilename()
fileIndex = matchingNode.GetFileIndex()
matches.PushBack(matchingNode)
}
log.Debugf("**********sequenceFor %v", NodeToString(matchingNode))
mapPairs, err := crossFunction(d, context.ChildContext(matches), expressionNode,
func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
node := &CandidateNode{Kind: MappingNode, Tag: "!!map"}
log.Debugf("**********adding key %v and value %v", NodeToString(lhs), NodeToString(rhs))
node.AddKeyValueChild(lhs, rhs)
node.document = document
node.fileIndex = fileIndex
node.filename = filename
return node, nil
}, false)
if err != nil {
return nil, err
}
innerList := listToNodeSeq(mapPairs.MatchingNodes)
innerList.Style = FlowStyle
innerList.document = document
innerList.fileIndex = fileIndex
innerList.filename = filename
return innerList, nil
}
// NOTE: here the document index gets dropped so we
// no longer know where the node originates from.
func listToNodeSeq(list *list.List) *CandidateNode {
node := CandidateNode{Kind: SequenceNode, Tag: "!!seq"}
for entry := list.Front(); entry != nil; entry = entry.Next() {
entryCandidate := entry.Value.(*CandidateNode)
log.Debugf("Collecting %v into sequence", NodeToString(entryCandidate))
node.AddChild(entryCandidate)
}
return &node
}