yq/pkg/yqlib/path_postfix.go

93 lines
3.2 KiB
Go
Raw Normal View History

2020-11-03 23:48:43 +00:00
package yqlib
2020-09-20 12:40:09 +00:00
import (
"errors"
2020-10-17 11:10:47 +00:00
2020-11-22 02:50:32 +00:00
logging "gopkg.in/op/go-logging.v1"
2020-09-20 12:40:09 +00:00
)
type pathPostFixerInterface interface {
ConvertToPostfix([]*token) ([]*Operation, error)
2020-09-20 12:40:09 +00:00
}
type pathPostFixer struct {
}
func newPathPostFixer() pathPostFixerInterface {
2020-09-20 12:40:09 +00:00
return &pathPostFixer{}
}
func popOpToResult(opStack []*token, result []*Operation) ([]*token, []*Operation) {
var newOp *token
2020-10-20 02:53:26 +00:00
opStack, newOp = opStack[0:len(opStack)-1], opStack[len(opStack)-1]
2020-10-20 04:33:20 +00:00
return opStack, append(result, newOp.Operation)
2020-09-20 12:40:09 +00:00
}
func (p *pathPostFixer) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) {
2020-10-20 04:33:20 +00:00
var result []*Operation
2020-09-20 12:40:09 +00:00
// surround the whole thing with quotes
var opStack = []*token{&token{TokenType: OpenBracket}}
var tokens = append(infixTokens, &token{TokenType: CloseBracket})
2020-09-20 12:40:09 +00:00
for _, currentToken := range tokens {
log.Debugf("postfix processing currentToken %v, %v", currentToken.toString(), currentToken.Operation)
switch currentToken.TokenType {
2020-10-21 02:54:51 +00:00
case OpenBracket, OpenCollect, OpenCollectObject:
opStack = append(opStack, currentToken)
2020-10-21 02:54:51 +00:00
case CloseCollect, CloseCollectObject:
var opener tokenType = OpenCollect
2020-10-21 02:54:51 +00:00
var collectOperator *OperationType = Collect
if currentToken.TokenType == CloseCollectObject {
2020-10-21 02:54:51 +00:00
opener = OpenCollectObject
collectOperator = CollectObject
}
2020-11-13 02:19:54 +00:00
itemsInMiddle := false
2020-10-21 02:54:51 +00:00
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener {
2020-10-16 01:29:26 +00:00
opStack, result = popOpToResult(opStack, result)
2020-11-13 02:19:54 +00:00
itemsInMiddle = true
}
if !itemsInMiddle {
// must be an empty collection, add the empty object as a LHS parameter
result = append(result, &Operation{OperationType: Empty})
2020-10-16 01:29:26 +00:00
}
if len(opStack) == 0 {
return nil, errors.New("Bad path expression, got close collect brackets without matching opening bracket")
}
2020-10-17 11:10:47 +00:00
// now we should have [] as the last element on the opStack, get rid of it
2020-10-16 01:29:26 +00:00
opStack = opStack[0 : len(opStack)-1]
//and append a collect to the opStack
opStack = append(opStack, &token{TokenType: OperationToken, Operation: &Operation{OperationType: ShortPipe}})
opStack = append(opStack, &token{TokenType: OperationToken, Operation: &Operation{OperationType: collectOperator}})
2020-10-11 00:24:22 +00:00
case CloseBracket:
2020-10-20 02:53:26 +00:00
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != OpenBracket {
2020-09-20 12:40:09 +00:00
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]
2020-10-11 00:24:22 +00:00
2020-10-10 04:24:37 +00:00
default:
var currentPrecedence = currentToken.Operation.OperationType.Precedence
2020-10-10 04:24:37 +00:00
// pop off higher precedent operators onto the result
2020-10-20 04:33:20 +00:00
for len(opStack) > 0 &&
opStack[len(opStack)-1].TokenType == OperationToken &&
opStack[len(opStack)-1].Operation.OperationType.Precedence >= currentPrecedence {
2020-10-10 04:24:37 +00:00
opStack, result = popOpToResult(opStack, result)
}
// add this operator to the opStack
opStack = append(opStack, currentToken)
2020-09-20 12:40:09 +00:00
}
}
2020-10-17 11:10:47 +00:00
if log.IsEnabledFor(logging.DEBUG) {
log.Debugf("PostFix Result:")
for _, currentToken := range result {
log.Debugf("> %v", currentToken.toString())
2020-10-17 11:10:47 +00:00
}
}
2020-09-20 12:40:09 +00:00
return result, nil
}