yq/pkg/yqlib/treeops/path_postfix.go

61 lines
2.0 KiB
Go

package treeops
import (
"errors"
)
type PathPostFixer interface {
ConvertToPostfix([]*Token) ([]*PathElement, error)
}
type pathPostFixer struct {
}
func NewPathPostFixer() PathPostFixer {
return &pathPostFixer{}
}
func popOpToResult(opStack []*Token, result []*PathElement) ([]*Token, []*PathElement) {
var operatorToPushToPostFix *Token
opStack, operatorToPushToPostFix = opStack[0:len(opStack)-1], opStack[len(opStack)-1]
var pathElement = PathElement{PathElementType: Operation, OperationType: operatorToPushToPostFix.OperationType}
return opStack, append(result, &pathElement)
}
func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*PathElement, error) {
var result []*PathElement
// surround the whole thing with quotes
var opStack = []*Token{&Token{PathElementType: OpenBracket, OperationType: None}}
var tokens = append(infixTokens, &Token{PathElementType: CloseBracket, OperationType: None})
for _, token := range tokens {
switch token.PathElementType {
case PathKey, ArrayIndex, SelfReference:
var pathElement = PathElement{PathElementType: token.PathElementType, Value: token.Value, StringValue: token.StringValue}
result = append(result, &pathElement)
case OpenBracket:
opStack = append(opStack, token)
case CloseBracket:
for len(opStack) > 0 && opStack[len(opStack)-1].PathElementType != OpenBracket {
opStack, result = popOpToResult(opStack, result)
}
if len(opStack) == 0 {
return nil, errors.New("Bad path expression, got close brackets without matching opening bracket")
}
// now we should have ( as the last element on the opStack, get rid of it
opStack = opStack[0 : len(opStack)-1]
default:
var currentPrecedence = token.OperationType.Precedence
// pop off higher precedent operators onto the result
for len(opStack) > 0 && opStack[len(opStack)-1].OperationType.Precedence >= currentPrecedence {
opStack, result = popOpToResult(opStack, result)
}
// add this operator to the opStack
opStack = append(opStack, token)
}
}
return result, nil
}