2020-11-03 23:48:43 +00:00
|
|
|
package yqlib
|
2020-11-02 00:20:38 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"container/list"
|
2022-11-11 03:53:45 +00:00
|
|
|
"fmt"
|
2020-11-02 00:20:38 +00:00
|
|
|
)
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
2020-12-22 01:22:59 +00:00
|
|
|
|
|
|
|
log.Debugf("AssignAlias operator!")
|
|
|
|
|
|
|
|
aliasName := ""
|
2021-01-12 23:18:53 +00:00
|
|
|
if !expressionNode.Operation.UpdateAssign {
|
2022-02-07 00:55:55 +00:00
|
|
|
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.RHS)
|
2021-01-06 09:30:48 +00:00
|
|
|
if err != nil {
|
2021-02-02 07:17:59 +00:00
|
|
|
return Context{}, err
|
2021-01-06 09:30:48 +00:00
|
|
|
}
|
2021-02-02 07:17:59 +00:00
|
|
|
if rhs.MatchingNodes.Front() != nil {
|
2023-04-08 11:42:46 +00:00
|
|
|
aliasName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value
|
2021-01-06 09:30:48 +00:00
|
|
|
}
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 00:55:55 +00:00
|
|
|
lhs, err := d.GetMatchingNodes(context, expressionNode.LHS)
|
2020-12-22 01:22:59 +00:00
|
|
|
|
|
|
|
if err != nil {
|
2021-02-02 07:17:59 +00:00
|
|
|
return Context{}, err
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() {
|
2020-12-22 01:22:59 +00:00
|
|
|
candidate := el.Value.(*CandidateNode)
|
|
|
|
log.Debugf("Setting aliasName : %v", candidate.GetKey())
|
2021-01-06 09:30:48 +00:00
|
|
|
|
2021-01-12 23:18:53 +00:00
|
|
|
if expressionNode.Operation.UpdateAssign {
|
2022-02-07 00:55:55 +00:00
|
|
|
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.RHS)
|
2021-01-06 09:30:48 +00:00
|
|
|
if err != nil {
|
2021-02-02 07:17:59 +00:00
|
|
|
return Context{}, err
|
2021-01-06 09:30:48 +00:00
|
|
|
}
|
2021-02-02 07:17:59 +00:00
|
|
|
if rhs.MatchingNodes.Front() != nil {
|
2023-04-08 11:42:46 +00:00
|
|
|
aliasName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value
|
2021-01-06 09:30:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-16 04:17:13 +00:00
|
|
|
if aliasName != "" {
|
2023-04-08 11:42:46 +00:00
|
|
|
candidate.Kind = AliasNode
|
|
|
|
candidate.Value = aliasName
|
2021-05-16 04:17:13 +00:00
|
|
|
}
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
2021-02-02 07:17:59 +00:00
|
|
|
return context, nil
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
func getAliasOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
2020-12-22 01:22:59 +00:00
|
|
|
log.Debugf("GetAlias operator!")
|
|
|
|
var results = list.New()
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
2020-12-22 01:22:59 +00:00
|
|
|
candidate := el.Value.(*CandidateNode)
|
2023-04-08 11:42:46 +00:00
|
|
|
result := candidate.CreateReplacement(ScalarNode, "!!str", candidate.Value)
|
2021-01-12 08:36:28 +00:00
|
|
|
results.PushBack(result)
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
2021-02-02 07:17:59 +00:00
|
|
|
return context.ChildContext(results), nil
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
func assignAnchorOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
2020-12-22 01:22:59 +00:00
|
|
|
|
|
|
|
log.Debugf("AssignAnchor operator!")
|
|
|
|
|
|
|
|
anchorName := ""
|
2021-01-12 23:18:53 +00:00
|
|
|
if !expressionNode.Operation.UpdateAssign {
|
2022-02-07 00:55:55 +00:00
|
|
|
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.RHS)
|
2021-01-06 09:30:48 +00:00
|
|
|
if err != nil {
|
2021-02-02 07:17:59 +00:00
|
|
|
return Context{}, err
|
2021-01-06 09:30:48 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
if rhs.MatchingNodes.Front() != nil {
|
2023-04-08 11:42:46 +00:00
|
|
|
anchorName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value
|
2021-01-06 09:30:48 +00:00
|
|
|
}
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 00:55:55 +00:00
|
|
|
lhs, err := d.GetMatchingNodes(context, expressionNode.LHS)
|
2020-12-22 01:22:59 +00:00
|
|
|
|
|
|
|
if err != nil {
|
2021-02-02 07:17:59 +00:00
|
|
|
return Context{}, err
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() {
|
2020-12-22 01:22:59 +00:00
|
|
|
candidate := el.Value.(*CandidateNode)
|
|
|
|
log.Debugf("Setting anchorName of : %v", candidate.GetKey())
|
2021-01-06 09:30:48 +00:00
|
|
|
|
2021-01-12 23:18:53 +00:00
|
|
|
if expressionNode.Operation.UpdateAssign {
|
2022-02-07 00:55:55 +00:00
|
|
|
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.RHS)
|
2021-01-06 09:30:48 +00:00
|
|
|
if err != nil {
|
2021-02-02 07:17:59 +00:00
|
|
|
return Context{}, err
|
2021-01-06 09:30:48 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
if rhs.MatchingNodes.Front() != nil {
|
2023-04-08 11:42:46 +00:00
|
|
|
anchorName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value
|
2021-01-06 09:30:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-08 11:42:46 +00:00
|
|
|
candidate.Anchor = anchorName
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
2021-02-02 07:17:59 +00:00
|
|
|
return context, nil
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
func getAnchorOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
2020-12-22 01:22:59 +00:00
|
|
|
log.Debugf("GetAnchor operator!")
|
|
|
|
var results = list.New()
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
2020-12-22 01:22:59 +00:00
|
|
|
candidate := el.Value.(*CandidateNode)
|
2023-04-08 11:42:46 +00:00
|
|
|
anchor := candidate.Anchor
|
|
|
|
result := candidate.CreateReplacement(ScalarNode, "!!str", anchor)
|
2021-01-12 08:36:28 +00:00
|
|
|
results.PushBack(result)
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
2021-02-02 07:17:59 +00:00
|
|
|
return context.ChildContext(results), nil
|
2020-12-22 01:22:59 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
func explodeOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
2020-11-02 00:20:38 +00:00
|
|
|
log.Debugf("-- ExplodeOperation")
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
2020-11-02 00:20:38 +00:00
|
|
|
candidate := el.Value.(*CandidateNode)
|
|
|
|
|
2022-02-07 00:55:55 +00:00
|
|
|
rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.RHS)
|
2020-11-02 00:20:38 +00:00
|
|
|
|
|
|
|
if err != nil {
|
2021-02-02 07:17:59 +00:00
|
|
|
return Context{}, err
|
2020-11-02 00:20:38 +00:00
|
|
|
}
|
2021-02-02 07:17:59 +00:00
|
|
|
for childEl := rhs.MatchingNodes.Front(); childEl != nil; childEl = childEl.Next() {
|
2023-04-08 11:42:46 +00:00
|
|
|
err = explodeNode(childEl.Value.(*CandidateNode), context)
|
2020-11-13 03:07:11 +00:00
|
|
|
if err != nil {
|
2021-02-02 07:17:59 +00:00
|
|
|
return Context{}, err
|
2020-11-13 03:07:11 +00:00
|
|
|
}
|
2020-11-02 00:20:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
return context, nil
|
2020-11-02 00:20:38 +00:00
|
|
|
}
|
|
|
|
|
2023-04-08 11:42:46 +00:00
|
|
|
func reconstructAliasedMap(node *CandidateNode, context Context) error {
|
2021-10-10 23:41:15 +00:00
|
|
|
var newContent = list.New()
|
|
|
|
// can I short cut here by prechecking if there's an anchor in the map?
|
|
|
|
// no it needs to recurse in overrideEntry.
|
|
|
|
|
|
|
|
for index := 0; index < len(node.Content); index = index + 2 {
|
|
|
|
keyNode := node.Content[index]
|
|
|
|
valueNode := node.Content[index+1]
|
|
|
|
log.Debugf("traversing %v", keyNode.Value)
|
|
|
|
if keyNode.Value != "<<" {
|
|
|
|
err := overrideEntry(node, keyNode, valueNode, index, context.ChildContext(newContent))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
2023-04-08 11:42:46 +00:00
|
|
|
if valueNode.Kind == SequenceNode {
|
2021-10-10 23:41:15 +00:00
|
|
|
log.Debugf("an alias merge list!")
|
|
|
|
for index := len(valueNode.Content) - 1; index >= 0; index = index - 1 {
|
|
|
|
aliasNode := valueNode.Content[index]
|
|
|
|
err := applyAlias(node, aliasNode.Alias, index, context.ChildContext(newContent))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Debugf("an alias merge!")
|
|
|
|
err := applyAlias(node, valueNode.Alias, index, context.ChildContext(newContent))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-09 03:51:21 +00:00
|
|
|
node.Content = make([]*CandidateNode, 0)
|
2021-10-10 23:41:15 +00:00
|
|
|
for newEl := newContent.Front(); newEl != nil; newEl = newEl.Next() {
|
2023-05-09 03:51:21 +00:00
|
|
|
node.AddChild(newEl.Value.(*CandidateNode))
|
2021-10-10 23:41:15 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-08 11:42:46 +00:00
|
|
|
func explodeNode(node *CandidateNode, context Context) error {
|
2023-04-15 05:07:23 +00:00
|
|
|
log.Debugf("explodeNode - %v", NodeToString(node))
|
2020-11-02 00:20:38 +00:00
|
|
|
node.Anchor = ""
|
|
|
|
switch node.Kind {
|
2023-06-05 22:27:59 +00:00
|
|
|
case SequenceNode:
|
2020-11-02 00:20:38 +00:00
|
|
|
for index, contentNode := range node.Content {
|
2023-04-15 05:07:23 +00:00
|
|
|
log.Debugf("explodeNode - index %v", index)
|
2021-02-02 07:17:59 +00:00
|
|
|
errorInContent := explodeNode(contentNode, context)
|
2020-11-02 00:20:38 +00:00
|
|
|
if errorInContent != nil {
|
|
|
|
return errorInContent
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2023-04-08 11:42:46 +00:00
|
|
|
case AliasNode:
|
2023-04-15 05:07:23 +00:00
|
|
|
log.Debugf("explodeNode - an alias to %v", NodeToString(node.Alias))
|
2020-11-02 00:20:38 +00:00
|
|
|
if node.Alias != nil {
|
|
|
|
node.Kind = node.Alias.Kind
|
|
|
|
node.Style = node.Alias.Style
|
|
|
|
node.Tag = node.Alias.Tag
|
2023-05-05 04:13:18 +00:00
|
|
|
node.AddChildren(node.Alias.Content)
|
2020-11-02 00:20:38 +00:00
|
|
|
node.Value = node.Alias.Value
|
|
|
|
node.Alias = nil
|
|
|
|
}
|
2023-04-15 05:07:23 +00:00
|
|
|
log.Debug("now I'm %v", NodeToString(node))
|
2020-11-02 00:20:38 +00:00
|
|
|
return nil
|
2023-04-08 11:42:46 +00:00
|
|
|
case MappingNode:
|
2021-10-10 23:41:15 +00:00
|
|
|
// //check the map has an alias in it
|
|
|
|
hasAlias := false
|
2020-11-02 00:20:38 +00:00
|
|
|
for index := 0; index < len(node.Content); index = index + 2 {
|
|
|
|
keyNode := node.Content[index]
|
2021-10-10 23:41:15 +00:00
|
|
|
if keyNode.Value == "<<" {
|
|
|
|
hasAlias = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if hasAlias {
|
|
|
|
// this is a slow op, which is why we want to check before running it.
|
|
|
|
return reconstructAliasedMap(node, context)
|
2021-12-20 22:30:08 +00:00
|
|
|
}
|
|
|
|
// this map has no aliases, but it's kids might
|
|
|
|
for index := 0; index < len(node.Content); index = index + 2 {
|
|
|
|
keyNode := node.Content[index]
|
|
|
|
valueNode := node.Content[index+1]
|
|
|
|
err := explodeNode(keyNode, context)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = explodeNode(valueNode, context)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-11-02 00:20:38 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-20 22:30:08 +00:00
|
|
|
return nil
|
2020-11-02 00:20:38 +00:00
|
|
|
default:
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-08 11:42:46 +00:00
|
|
|
func applyAlias(node *CandidateNode, alias *CandidateNode, aliasIndex int, newContent Context) error {
|
2023-04-15 04:24:39 +00:00
|
|
|
log.Debug("alias is nil ?")
|
2020-11-02 00:20:38 +00:00
|
|
|
if alias == nil {
|
2020-11-02 02:43:45 +00:00
|
|
|
return nil
|
2020-11-02 00:20:38 +00:00
|
|
|
}
|
2023-04-15 04:24:39 +00:00
|
|
|
log.Debug("alias: %v", NodeToString(alias))
|
2023-04-08 11:42:46 +00:00
|
|
|
if alias.Kind != MappingNode {
|
2022-11-11 03:53:45 +00:00
|
|
|
return fmt.Errorf("merge anchor only supports maps, got %v instead", alias.Tag)
|
|
|
|
}
|
2020-11-02 00:20:38 +00:00
|
|
|
for index := 0; index < len(alias.Content); index = index + 2 {
|
|
|
|
keyNode := alias.Content[index]
|
|
|
|
log.Debugf("applying alias key %v", keyNode.Value)
|
|
|
|
valueNode := alias.Content[index+1]
|
2020-11-02 02:43:45 +00:00
|
|
|
err := overrideEntry(node, keyNode, valueNode, aliasIndex, newContent)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-11-02 00:20:38 +00:00
|
|
|
}
|
2020-11-02 02:43:45 +00:00
|
|
|
return nil
|
2020-11-02 00:20:38 +00:00
|
|
|
}
|
|
|
|
|
2023-04-08 11:42:46 +00:00
|
|
|
func overrideEntry(node *CandidateNode, key *CandidateNode, value *CandidateNode, startIndex int, newContent Context) error {
|
2020-11-02 02:43:45 +00:00
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
err := explodeNode(value, newContent)
|
2020-11-02 02:43:45 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
for newEl := newContent.MatchingNodes.Front(); newEl != nil; newEl = newEl.Next() {
|
2020-11-02 02:43:45 +00:00
|
|
|
valueEl := newEl.Next() // move forward twice
|
2023-04-15 04:24:39 +00:00
|
|
|
keyNode := newEl.Value.(*CandidateNode)
|
|
|
|
log.Debugf("checking new content %v:%v", keyNode.Value, valueEl.Value.(*CandidateNode).Value)
|
2020-11-02 02:43:45 +00:00
|
|
|
if keyNode.Value == key.Value && keyNode.Alias == nil && key.Alias == nil {
|
|
|
|
log.Debugf("overridign new content")
|
|
|
|
valueEl.Value = value
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
newEl = valueEl // move forward twice
|
|
|
|
}
|
|
|
|
|
|
|
|
for index := startIndex + 2; index < len(node.Content); index = index + 2 {
|
2020-11-02 00:20:38 +00:00
|
|
|
keyNode := node.Content[index]
|
2020-11-02 02:43:45 +00:00
|
|
|
|
|
|
|
if keyNode.Value == key.Value && keyNode.Alias == nil {
|
|
|
|
log.Debugf("content will be overridden at index %v", index)
|
|
|
|
return nil
|
2020-11-02 00:20:38 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-02 02:43:45 +00:00
|
|
|
|
2021-02-02 07:17:59 +00:00
|
|
|
err = explodeNode(key, newContent)
|
2020-11-02 02:43:45 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.Debugf("adding %v:%v", key.Value, value.Value)
|
2021-02-02 07:17:59 +00:00
|
|
|
newContent.MatchingNodes.PushBack(key)
|
|
|
|
newContent.MatchingNodes.PushBack(value)
|
2020-11-02 02:43:45 +00:00
|
|
|
return nil
|
2020-11-02 00:20:38 +00:00
|
|
|
}
|