mirror of
https://github.com/mikefarah/yq.git
synced 2025-01-13 20:15:57 +00:00
binary tree ftw
This commit is contained in:
parent
5ee52f9506
commit
f7d4695837
@ -1,23 +1,73 @@
|
|||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
// import yaml "gopkg.in/yaml.v3"
|
type dataTreeNavigator struct {
|
||||||
|
}
|
||||||
|
|
||||||
// type NodeLeafContext struct {
|
type DataTreeNavigator interface {
|
||||||
// Node *yaml.Node
|
GetMatchingNodes(matchingNodes []*NodeContext, pathNode *PathTreeNode) ([]*NodeContext, error)
|
||||||
// Head interface{}
|
}
|
||||||
// PathStack []interface{}
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func newNodeLeafContext(node *yaml.Node, head interface{}, tailpathStack []interface{}) NodeLeafContext {
|
func NewTreeNavigator() DataTreeNavigator {
|
||||||
// newPathStack := make([]interface{}, len(pathStack))
|
return &dataTreeNavigator{}
|
||||||
// copy(newPathStack, pathStack)
|
}
|
||||||
// return NodeContext{
|
|
||||||
// Node: node,
|
|
||||||
// Head: head,
|
|
||||||
// PathStack: newPathStack,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type DataTreeNavigator interface {
|
func (d *dataTreeNavigator) traverseSingle(matchingNode *NodeContext, pathNode *PathElement) ([]*NodeContext, error) {
|
||||||
// Traverse(value *NodeLeafContext)
|
var value = matchingNode.Node
|
||||||
// }
|
// match all for splat
|
||||||
|
// match all and recurse for deep
|
||||||
|
// etc and so forth
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dataTreeNavigator) traverse(matchingNodes []*NodeContext, pathNode *PathElement) ([]*NodeContext, error) {
|
||||||
|
var newMatchingNodes = make([]*NodeContext, 0)
|
||||||
|
var newNodes []*NodeContext
|
||||||
|
var err error
|
||||||
|
for _, node := range matchingNodes {
|
||||||
|
|
||||||
|
newNodes, err = d.traverseSingle(node, pathNode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newMatchingNodes = append(newMatchingNodes, newNodes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newMatchingNodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes []*NodeContext, pathNode *PathTreeNode) ([]*NodeContext, error) {
|
||||||
|
if pathNode.PathElement.PathElementType == PathKey || pathNode.PathElement.PathElementType == ArrayIndex {
|
||||||
|
return d.traverse(matchingNodes, pathNode.PathElement)
|
||||||
|
} else {
|
||||||
|
var lhs, rhs []*NodeContext
|
||||||
|
var err error
|
||||||
|
switch pathNode.PathElement.OperationType {
|
||||||
|
case Traverse:
|
||||||
|
lhs, err = d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.GetMatchingNodes(lhs, pathNode.Rhs)
|
||||||
|
case Or, And:
|
||||||
|
lhs, err = d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rhs, err = d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.setFunction(pathNode.PathElement, lhs, rhs), nil
|
||||||
|
case Equals:
|
||||||
|
lhs, err = d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.findMatchingValues(lhs, pathNode.Rhs)
|
||||||
|
case EqualsSelf:
|
||||||
|
return d.findMatchingValues(matchingNodes, pathNode.Rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -32,7 +32,6 @@ type PathElement struct {
|
|||||||
PathElementType PathElementType
|
PathElementType PathElementType
|
||||||
OperationType OperationType
|
OperationType OperationType
|
||||||
Value interface{}
|
Value interface{}
|
||||||
Finished bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// debugging purposes only
|
// debugging purposes only
|
||||||
@ -109,14 +108,6 @@ func popOpToResult(opStack []*lex.Token, result []*PathElement) ([]*lex.Token, [
|
|||||||
return opStack, append(result, &pathElement)
|
return opStack, append(result, &pathElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
func finishPathKey(result []*PathElement) {
|
|
||||||
if len(result) > 0 {
|
|
||||||
//need to mark PathKey elements as finished so we
|
|
||||||
//stop appending PathKeys as children
|
|
||||||
result[len(result)-1].Finished = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *pathPostFixer) ConvertToPostfix(infixTokens []*lex.Token) ([]*PathElement, error) {
|
func (p *pathPostFixer) ConvertToPostfix(infixTokens []*lex.Token) ([]*PathElement, error) {
|
||||||
var result []*PathElement
|
var result []*PathElement
|
||||||
// surround the whole thing with quotes
|
// surround the whole thing with quotes
|
||||||
@ -130,7 +121,6 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*lex.Token) ([]*PathEleme
|
|||||||
result = append(result, &pathElement)
|
result = append(result, &pathElement)
|
||||||
case TokenIds["("]:
|
case TokenIds["("]:
|
||||||
opStack = append(opStack, token)
|
opStack = append(opStack, token)
|
||||||
finishPathKey(result)
|
|
||||||
case TokenIds["OR_OPERATOR"], TokenIds["AND_OPERATOR"], TokenIds["EQUALS_OPERATOR"], TokenIds["EQUALS_SELF_OPERATOR"], TokenIds["TRAVERSE_OPERATOR"]:
|
case TokenIds["OR_OPERATOR"], TokenIds["AND_OPERATOR"], TokenIds["EQUALS_OPERATOR"], TokenIds["EQUALS_SELF_OPERATOR"], TokenIds["TRAVERSE_OPERATOR"]:
|
||||||
var currentPrecedence = precedenceMap[token.Type]
|
var currentPrecedence = precedenceMap[token.Type]
|
||||||
// pop off higher precedent operators onto the result
|
// pop off higher precedent operators onto the result
|
||||||
@ -139,7 +129,6 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*lex.Token) ([]*PathEleme
|
|||||||
}
|
}
|
||||||
// add this operator to the opStack
|
// add this operator to the opStack
|
||||||
opStack = append(opStack, token)
|
opStack = append(opStack, token)
|
||||||
finishPathKey(result)
|
|
||||||
case TokenIds[")"]:
|
case TokenIds[")"]:
|
||||||
for len(opStack) > 0 && opStack[len(opStack)-1].Type != TokenIds["("] {
|
for len(opStack) > 0 && opStack[len(opStack)-1].Type != TokenIds["("] {
|
||||||
opStack, result = popOpToResult(opStack, result)
|
opStack, result = popOpToResult(opStack, result)
|
||||||
@ -149,7 +138,6 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*lex.Token) ([]*PathEleme
|
|||||||
}
|
}
|
||||||
// now we should have ( as the last element on the opStack, get rid of it
|
// now we should have ( as the last element on the opStack, get rid of it
|
||||||
opStack = opStack[0 : len(opStack)-1]
|
opStack = opStack[0 : len(opStack)-1]
|
||||||
finishPathKey(result)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
|
@ -1,27 +1,39 @@
|
|||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
import lex "github.com/timtadh/lexmachine"
|
import "fmt"
|
||||||
|
|
||||||
func parseTree(tokens []*lex.Token, currentElement *PathElement, allElements []*PathElement) []*PathElement {
|
|
||||||
currentToken, remainingTokens := tokens[0], tokens[1:]
|
|
||||||
|
|
||||||
switch currentToken.Type {
|
|
||||||
case TokenIds["PATH_KEY"]:
|
|
||||||
currentElement.PathElementType = PathKey
|
|
||||||
currentElement.OperationType = None
|
|
||||||
currentElement.Value = currentToken.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(remainingTokens) == 0 {
|
|
||||||
return append(allElements, currentElement)
|
|
||||||
}
|
|
||||||
return parseTree(remainingTokens, &PathElement{}, append(allElements, currentElement))
|
|
||||||
|
|
||||||
|
type PathTreeNode struct {
|
||||||
|
PathElement *PathElement
|
||||||
|
Lhs *PathTreeNode
|
||||||
|
Rhs *PathTreeNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTree(tokens []*lex.Token) []*PathElement {
|
type PathTreeCreator interface {
|
||||||
if len(tokens) == 0 {
|
CreatePathTree([]*PathElement) (*PathTreeNode, error)
|
||||||
return make([]*PathElement, 0)
|
}
|
||||||
}
|
|
||||||
return parseTree(tokens, &PathElement{}, make([]*PathElement, 0))
|
type pathTreeCreator struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPathTreeCreator() PathTreeCreator {
|
||||||
|
return &pathTreeCreator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pathTreeCreator) CreatePathTree(postFixPath []*PathElement) (*PathTreeNode, error) {
|
||||||
|
var stack = make([]*PathTreeNode, 0)
|
||||||
|
|
||||||
|
for _, pathElement := range postFixPath {
|
||||||
|
var newNode = PathTreeNode{PathElement: pathElement}
|
||||||
|
if pathElement.PathElementType == Operation {
|
||||||
|
remaining, lhs, rhs := stack[:len(stack)-2], stack[len(stack)-2], stack[len(stack)-1]
|
||||||
|
newNode.Lhs = lhs
|
||||||
|
newNode.Rhs = rhs
|
||||||
|
stack = remaining
|
||||||
|
}
|
||||||
|
stack = append(stack, &newNode)
|
||||||
|
}
|
||||||
|
if len(stack) != 1 {
|
||||||
|
return nil, fmt.Errorf("expected stack to have 1 thing but its %v", stack)
|
||||||
|
}
|
||||||
|
return stack[0], nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user