mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-12 05:38:04 +00:00
Fixing op precedences
This commit is contained in:
parent
85ec32e3db
commit
9e56b364c2
@ -79,14 +79,3 @@ then
|
||||
yq eval '.a.[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
- path:
|
||||
- a
|
||||
- 1
|
||||
value: dog
|
||||
- path:
|
||||
- a
|
||||
- 2
|
||||
value: frog
|
||||
```
|
||||
|
||||
|
@ -20,20 +20,22 @@ func newExpressionPostFixer() expressionPostFixer {
|
||||
func popOpToResult(opStack []*token, result []*Operation) ([]*token, []*Operation) {
|
||||
var newOp *token
|
||||
opStack, newOp = opStack[0:len(opStack)-1], opStack[len(opStack)-1]
|
||||
log.Debugf("popped %v from opstack to results", newOp.toString(true))
|
||||
return opStack, append(result, newOp.Operation)
|
||||
}
|
||||
|
||||
func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) {
|
||||
var result []*Operation
|
||||
// surround the whole thing with quotes
|
||||
// surround the whole thing with brackets
|
||||
var opStack = []*token{{TokenType: openBracket}}
|
||||
var tokens = append(infixTokens, &token{TokenType: closeBracket})
|
||||
|
||||
for _, currentToken := range tokens {
|
||||
log.Debugf("postfix processing currentToken %v, %v", currentToken.toString(), currentToken.Operation)
|
||||
log.Debugf("postfix processing currentToken %v", currentToken.toString(true))
|
||||
switch currentToken.TokenType {
|
||||
case openBracket, openCollect, openCollectObject:
|
||||
opStack = append(opStack, currentToken)
|
||||
log.Debugf("put %v onto the opstack", currentToken.toString(true))
|
||||
case closeCollect, closeCollectObject:
|
||||
var opener tokenType = openCollect
|
||||
var collectOperator *operationType = collectOpType
|
||||
@ -49,15 +51,26 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope
|
||||
if !itemsInMiddle {
|
||||
// must be an empty collection, add the empty object as a LHS parameter
|
||||
result = append(result, &Operation{OperationType: emptyOpType})
|
||||
log.Debugf("put EMPTY onto the result")
|
||||
}
|
||||
if len(opStack) == 0 {
|
||||
return nil, errors.New("Bad path expression, got close collect brackets without matching opening bracket")
|
||||
}
|
||||
// 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]
|
||||
log.Debugf("deleteing open bracket from opstack")
|
||||
|
||||
//and append a collect to the opStack
|
||||
opStack = append(opStack, &token{TokenType: operationToken, Operation: &Operation{OperationType: shortPipeOpType}})
|
||||
opStack = append(opStack, &token{TokenType: operationToken, Operation: &Operation{OperationType: collectOperator}})
|
||||
//WHY AM I NOT PUTTING THIS STRAIGHT ONTO THE RESULT LIKE EMPTY?
|
||||
result = append(result, &Operation{OperationType: collectOperator})
|
||||
log.Debugf("put collect onto the result")
|
||||
result = append(result, &Operation{OperationType: shortPipeOpType})
|
||||
log.Debugf("put shortpipe onto the result")
|
||||
|
||||
// opStack = append(opStack, &token{TokenType: operationToken, Operation: &Operation{OperationType: shortPipeOpType}})
|
||||
// log.Debugf("put shortPipe onto the opstack")
|
||||
// opStack = append(opStack, &token{TokenType: operationToken, Operation: &Operation{OperationType: collectOperator}})
|
||||
// log.Debugf("put collect onto the opstack")
|
||||
case closeBracket:
|
||||
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != openBracket {
|
||||
opStack, result = popOpToResult(opStack, result)
|
||||
@ -73,11 +86,12 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope
|
||||
// pop off higher precedent operators onto the result
|
||||
for len(opStack) > 0 &&
|
||||
opStack[len(opStack)-1].TokenType == operationToken &&
|
||||
opStack[len(opStack)-1].Operation.OperationType.Precedence >= currentPrecedence {
|
||||
opStack[len(opStack)-1].Operation.OperationType.Precedence > currentPrecedence {
|
||||
opStack, result = popOpToResult(opStack, result)
|
||||
}
|
||||
// add this operator to the opStack
|
||||
opStack = append(opStack, currentToken)
|
||||
log.Debugf("put %v onto the opstack", currentToken.toString(true))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,11 @@ var pathTests = []struct {
|
||||
expectedTokens []interface{}
|
||||
expectedPostFix []interface{}
|
||||
}{
|
||||
{
|
||||
`.a | .b | .c`,
|
||||
append(make([]interface{}, 0), "a", "PIPE", "b", "PIPE", "c"),
|
||||
append(make([]interface{}, 0), "a", "b", "c", "PIPE", "PIPE"),
|
||||
},
|
||||
{
|
||||
`[]`,
|
||||
append(make([]interface{}, 0), "[", "]"),
|
||||
@ -190,7 +195,7 @@ func TestPathParsing(t *testing.T) {
|
||||
}
|
||||
var tokenValues []interface{}
|
||||
for _, token := range tokens {
|
||||
tokenValues = append(tokenValues, token.toString())
|
||||
tokenValues = append(tokenValues, token.toString(false))
|
||||
}
|
||||
test.AssertResultComplexWithContext(t, tt.expectedTokens, tokenValues, fmt.Sprintf("tokenise: %v", tt.path))
|
||||
|
||||
|
@ -34,9 +34,11 @@ type token struct {
|
||||
|
||||
}
|
||||
|
||||
func (t *token) toString() string {
|
||||
func (t *token) toString(detail bool) string {
|
||||
if t.TokenType == operationToken {
|
||||
log.Debug("toString, its an op")
|
||||
if detail {
|
||||
return fmt.Sprintf("%v (%v)", t.Operation.toString(), t.Operation.OperationType.Precedence)
|
||||
}
|
||||
return t.Operation.toString()
|
||||
} else if t.TokenType == openBracket {
|
||||
return "("
|
||||
@ -354,7 +356,7 @@ func (p *expressionTokeniserImpl) Tokenise(expression string) ([]*token, error)
|
||||
|
||||
if tok != nil {
|
||||
currentToken := tok.(*token)
|
||||
log.Debugf("Tokenising %v", currentToken.toString())
|
||||
log.Debugf("Tokenising %v", currentToken.toString(true))
|
||||
tokens = append(tokens, currentToken)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -72,10 +72,10 @@ var splitStringOpType = &operationType{Type: "SPLIT", NumArgs: 1, Precedence: 50
|
||||
var keysOpType = &operationType{Type: "KEYS", NumArgs: 0, Precedence: 50, Handler: keysOperator}
|
||||
|
||||
var collectObjectOpType = &operationType{Type: "COLLECT_OBJECT", NumArgs: 0, Precedence: 50, Handler: collectObjectOperator}
|
||||
var traversePathOpType = &operationType{Type: "TRAVERSE_PATH", NumArgs: 0, Precedence: 50, Handler: traversePathOperator}
|
||||
var traversePathOpType = &operationType{Type: "TRAVERSE_PATH", NumArgs: 0, Precedence: 51, Handler: traversePathOperator}
|
||||
var traverseArrayOpType = &operationType{Type: "TRAVERSE_ARRAY", NumArgs: 2, Precedence: 50, Handler: traverseArrayOperator}
|
||||
|
||||
var selfReferenceOpType = &operationType{Type: "SELF", NumArgs: 0, Precedence: 50, Handler: selfOperator}
|
||||
var selfReferenceOpType = &operationType{Type: "SELF", NumArgs: 0, Precedence: 51, Handler: selfOperator}
|
||||
var valueOpType = &operationType{Type: "VALUE", NumArgs: 0, Precedence: 50, Handler: valueOperator}
|
||||
var envOpType = &operationType{Type: "ENV", NumArgs: 0, Precedence: 50, Handler: envOperator}
|
||||
var notOpType = &operationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: notOperator}
|
||||
|
Loading…
Reference in New Issue
Block a user