mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-12 13:48:06 +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
|
yq eval '.a.[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
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) {
|
func popOpToResult(opStack []*token, result []*Operation) ([]*token, []*Operation) {
|
||||||
var newOp *token
|
var newOp *token
|
||||||
opStack, newOp = opStack[0:len(opStack)-1], opStack[len(opStack)-1]
|
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)
|
return opStack, append(result, newOp.Operation)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) {
|
func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) {
|
||||||
var result []*Operation
|
var result []*Operation
|
||||||
// surround the whole thing with quotes
|
// surround the whole thing with brackets
|
||||||
var opStack = []*token{{TokenType: openBracket}}
|
var opStack = []*token{{TokenType: openBracket}}
|
||||||
var tokens = append(infixTokens, &token{TokenType: closeBracket})
|
var tokens = append(infixTokens, &token{TokenType: closeBracket})
|
||||||
|
|
||||||
for _, currentToken := range tokens {
|
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 {
|
switch currentToken.TokenType {
|
||||||
case openBracket, openCollect, openCollectObject:
|
case openBracket, openCollect, openCollectObject:
|
||||||
opStack = append(opStack, currentToken)
|
opStack = append(opStack, currentToken)
|
||||||
|
log.Debugf("put %v onto the opstack", currentToken.toString(true))
|
||||||
case closeCollect, closeCollectObject:
|
case closeCollect, closeCollectObject:
|
||||||
var opener tokenType = openCollect
|
var opener tokenType = openCollect
|
||||||
var collectOperator *operationType = collectOpType
|
var collectOperator *operationType = collectOpType
|
||||||
@ -49,15 +51,26 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope
|
|||||||
if !itemsInMiddle {
|
if !itemsInMiddle {
|
||||||
// must be an empty collection, add the empty object as a LHS parameter
|
// must be an empty collection, add the empty object as a LHS parameter
|
||||||
result = append(result, &Operation{OperationType: emptyOpType})
|
result = append(result, &Operation{OperationType: emptyOpType})
|
||||||
|
log.Debugf("put EMPTY onto the result")
|
||||||
}
|
}
|
||||||
if len(opStack) == 0 {
|
if len(opStack) == 0 {
|
||||||
return nil, errors.New("Bad path expression, got close collect brackets without matching opening bracket")
|
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]
|
opStack = opStack[0 : len(opStack)-1]
|
||||||
|
log.Debugf("deleteing open bracket from opstack")
|
||||||
|
|
||||||
//and append a collect to the opStack
|
//and append a collect to the opStack
|
||||||
opStack = append(opStack, &token{TokenType: operationToken, Operation: &Operation{OperationType: shortPipeOpType}})
|
//WHY AM I NOT PUTTING THIS STRAIGHT ONTO THE RESULT LIKE EMPTY?
|
||||||
opStack = append(opStack, &token{TokenType: operationToken, Operation: &Operation{OperationType: collectOperator}})
|
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:
|
case closeBracket:
|
||||||
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != openBracket {
|
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != openBracket {
|
||||||
opStack, result = popOpToResult(opStack, result)
|
opStack, result = popOpToResult(opStack, result)
|
||||||
@ -73,11 +86,12 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope
|
|||||||
// pop off higher precedent operators onto the result
|
// pop off higher precedent operators onto the result
|
||||||
for len(opStack) > 0 &&
|
for len(opStack) > 0 &&
|
||||||
opStack[len(opStack)-1].TokenType == operationToken &&
|
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)
|
opStack, result = popOpToResult(opStack, result)
|
||||||
}
|
}
|
||||||
// add this operator to the opStack
|
// add this operator to the opStack
|
||||||
opStack = append(opStack, currentToken)
|
opStack = append(opStack, currentToken)
|
||||||
|
log.Debugf("put %v onto the opstack", currentToken.toString(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,11 @@ var pathTests = []struct {
|
|||||||
expectedTokens []interface{}
|
expectedTokens []interface{}
|
||||||
expectedPostFix []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), "[", "]"),
|
append(make([]interface{}, 0), "[", "]"),
|
||||||
@ -190,7 +195,7 @@ func TestPathParsing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
var tokenValues []interface{}
|
var tokenValues []interface{}
|
||||||
for _, token := range tokens {
|
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))
|
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 {
|
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()
|
return t.Operation.toString()
|
||||||
} else if t.TokenType == openBracket {
|
} else if t.TokenType == openBracket {
|
||||||
return "("
|
return "("
|
||||||
@ -354,7 +356,7 @@ func (p *expressionTokeniserImpl) Tokenise(expression string) ([]*token, error)
|
|||||||
|
|
||||||
if tok != nil {
|
if tok != nil {
|
||||||
currentToken := tok.(*token)
|
currentToken := tok.(*token)
|
||||||
log.Debugf("Tokenising %v", currentToken.toString())
|
log.Debugf("Tokenising %v", currentToken.toString(true))
|
||||||
tokens = append(tokens, currentToken)
|
tokens = append(tokens, currentToken)
|
||||||
}
|
}
|
||||||
if err != nil {
|
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 keysOpType = &operationType{Type: "KEYS", NumArgs: 0, Precedence: 50, Handler: keysOperator}
|
||||||
|
|
||||||
var collectObjectOpType = &operationType{Type: "COLLECT_OBJECT", NumArgs: 0, Precedence: 50, Handler: collectObjectOperator}
|
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 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 valueOpType = &operationType{Type: "VALUE", NumArgs: 0, Precedence: 50, Handler: valueOperator}
|
||||||
var envOpType = &operationType{Type: "ENV", NumArgs: 0, Precedence: 50, Handler: envOperator}
|
var envOpType = &operationType{Type: "ENV", NumArgs: 0, Precedence: 50, Handler: envOperator}
|
||||||
var notOpType = &operationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: notOperator}
|
var notOpType = &operationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: notOperator}
|
||||||
|
Loading…
Reference in New Issue
Block a user