mirror of
				https://github.com/taigrr/yq
				synced 2025-01-18 04:53:17 -08:00 
			
		
		
		
	Fixing op precedences
This commit is contained in:
		
							parent
							
								
									35c97e832e
								
							
						
					
					
						commit
						07b053f040
					
				| @ -79,3 +79,14 @@ then | ||||
| yq eval '.a.[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml | ||||
| ``` | ||||
| will output | ||||
| ```yaml | ||||
| - path: | ||||
|     - a | ||||
|     - 1 | ||||
|   value: dog | ||||
| - path: | ||||
|     - a | ||||
|     - 2 | ||||
|   value: frog | ||||
| ``` | ||||
| 
 | ||||
|  | ||||
| @ -70,7 +70,7 @@ func (p *expressionParserImpl) createExpressionTree(postFixPath []*Operation) (* | ||||
| 		stack = append(stack, &newNode) | ||||
| 	} | ||||
| 	if len(stack) != 1 { | ||||
| 		return nil, fmt.Errorf("expected end of expression but found '%v', please check expression syntax", strings.TrimSpace(stack[1].Operation.StringValue)) | ||||
| 		return nil, fmt.Errorf("Bad expression, please check expression syntax") | ||||
| 	} | ||||
| 	return stack[0], nil | ||||
| } | ||||
|  | ||||
| @ -38,5 +38,5 @@ func TestPathTreeOneArgForOneArgOp(t *testing.T) { | ||||
| 
 | ||||
| func TestPathTreeExtraArgs(t *testing.T) { | ||||
| 	_, err := NewExpressionParser().ParseExpression("sortKeys(.) explode(.)") | ||||
| 	test.AssertResultComplex(t, "expected end of expression but found 'explode', please check expression syntax", err.Error()) | ||||
| 	test.AssertResultComplex(t, "Bad expression, please check expression syntax", err.Error()) | ||||
| } | ||||
|  | ||||
| @ -43,15 +43,9 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope | ||||
| 				opener = openCollectObject | ||||
| 				collectOperator = collectObjectOpType | ||||
| 			} | ||||
| 			itemsInMiddle := false | ||||
| 
 | ||||
| 			for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener { | ||||
| 				opStack, result = popOpToResult(opStack, result) | ||||
| 				itemsInMiddle = true | ||||
| 			} | ||||
| 			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") | ||||
| @ -61,16 +55,11 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope | ||||
| 			log.Debugf("deleteing open bracket from opstack") | ||||
| 
 | ||||
| 			//and append a collect to the opStack | ||||
| 			//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) | ||||
|  | ||||
| @ -19,9 +19,19 @@ var pathTests = []struct { | ||||
| 	}, | ||||
| 	{ | ||||
| 		`[]`, | ||||
| 		append(make([]interface{}, 0), "[", "]"), | ||||
| 		append(make([]interface{}, 0), "[", "EMPTY", "]"), | ||||
| 		append(make([]interface{}, 0), "EMPTY", "COLLECT", "SHORT_PIPE"), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`{}`, | ||||
| 		append(make([]interface{}, 0), "{", "EMPTY", "}"), | ||||
| 		append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "SHORT_PIPE"), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`[{}]`, // [{}] | ||||
| 		append(make([]interface{}, 0), "[", "{", "EMPTY", "}", "]"), | ||||
| 		append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "SHORT_PIPE", "COLLECT", "SHORT_PIPE"), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`.b[.a]`, | ||||
| 		append(make([]interface{}, 0), "b", "TRAVERSE_ARRAY", "[", "a", "]"), | ||||
| @ -29,17 +39,17 @@ var pathTests = []struct { | ||||
| 	}, | ||||
| 	{ | ||||
| 		`.[]`, | ||||
| 		append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "]"), | ||||
| 		append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]"), | ||||
| 		append(make([]interface{}, 0), "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`.a[]`, | ||||
| 		append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "]"), | ||||
| 		append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "EMPTY", "]"), | ||||
| 		append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`.a.[]`, | ||||
| 		append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "]"), | ||||
| 		append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "EMPTY", "]"), | ||||
| 		append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), | ||||
| 	}, | ||||
| 	{ | ||||
| @ -54,7 +64,7 @@ var pathTests = []struct { | ||||
| 	}, | ||||
| 	{ | ||||
| 		`.a[].c`, | ||||
| 		append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "]", "SHORT_PIPE", "c"), | ||||
| 		append(make([]interface{}, 0), "a", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "SHORT_PIPE", "c"), | ||||
| 		append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "c", "SHORT_PIPE"), | ||||
| 	}, | ||||
| 	{ | ||||
| @ -79,17 +89,17 @@ var pathTests = []struct { | ||||
| 	}, | ||||
| 	{ | ||||
| 		`.a | .[].b == "apple"`, | ||||
| 		append(make([]interface{}, 0), "a", "PIPE", "SELF", "TRAVERSE_ARRAY", "[", "]", "SHORT_PIPE", "b", "EQUALS", "apple (string)"), | ||||
| 		append(make([]interface{}, 0), "a", "PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "SHORT_PIPE", "b", "EQUALS", "apple (string)"), | ||||
| 		append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "apple (string)", "EQUALS", "PIPE"), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`(.a | .[].b) == "apple"`, | ||||
| 		append(make([]interface{}, 0), "(", "a", "PIPE", "SELF", "TRAVERSE_ARRAY", "[", "]", "SHORT_PIPE", "b", ")", "EQUALS", "apple (string)"), | ||||
| 		append(make([]interface{}, 0), "(", "a", "PIPE", "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "SHORT_PIPE", "b", ")", "EQUALS", "apple (string)"), | ||||
| 		append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "PIPE", "apple (string)", "EQUALS"), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`.[] | select(. == "*at")`, | ||||
| 		append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "]", "PIPE", "SELECT", "(", "SELF", "EQUALS", "*at (string)", ")"), | ||||
| 		append(make([]interface{}, 0), "SELF", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "PIPE", "SELECT", "(", "SELF", "EQUALS", "*at (string)", ")"), | ||||
| 		append(make([]interface{}, 0), "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SELF", "*at (string)", "EQUALS", "SELECT", "PIPE"), | ||||
| 	}, | ||||
| 	{ | ||||
| @ -124,7 +134,7 @@ var pathTests = []struct { | ||||
| 	}, | ||||
| 	{ | ||||
| 		`{.a: .c, .b.[]: .f.g[]}`, | ||||
| 		append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "c", "UNION", "b", "TRAVERSE_ARRAY", "[", "]", "CREATE_MAP", "f", "SHORT_PIPE", "g", "TRAVERSE_ARRAY", "[", "]", "}"), | ||||
| 		append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "c", "UNION", "b", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "CREATE_MAP", "f", "SHORT_PIPE", "g", "TRAVERSE_ARRAY", "[", "EMPTY", "]", "}"), | ||||
| 		append(make([]interface{}, 0), "a", "c", "CREATE_MAP", "b", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "f", "g", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE", "CREATE_MAP", "UNION", "COLLECT_OBJECT", "SHORT_PIPE"), | ||||
| 	}, | ||||
| 	{ | ||||
| @ -177,11 +187,6 @@ var pathTests = []struct { | ||||
| 		append(make([]interface{}, 0), "foo*", "PIPE", "(", "SELF", "ASSIGN_STYLE", "flow (string)", ")"), | ||||
| 		append(make([]interface{}, 0), "foo*", "SELF", "flow (string)", "ASSIGN_STYLE", "PIPE"), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`{}`, | ||||
| 		append(make([]interface{}, 0), "{", "}"), | ||||
| 		append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "SHORT_PIPE"), | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| var tokeniser = newExpressionTokeniser() | ||||
|  | ||||
| @ -409,6 +409,14 @@ func (p *expressionTokeniserImpl) handleToken(tokens []*token, index int, postPr | ||||
| 
 | ||||
| 	postProcessedTokens = append(postProcessedTokens, currentToken) | ||||
| 
 | ||||
| 	if index != len(tokens)-1 && | ||||
| 		((currentToken.TokenType == openCollect && tokens[index+1].TokenType == closeCollect) || | ||||
| 			(currentToken.TokenType == openCollectObject && tokens[index+1].TokenType == closeCollectObject)) { | ||||
| 
 | ||||
| 		op := &Operation{OperationType: emptyOpType, StringValue: "EMPTY"} | ||||
| 		postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op}) | ||||
| 	} | ||||
| 
 | ||||
| 	if index != len(tokens)-1 && currentToken.CheckForPostTraverse && | ||||
| 		tokens[index+1].TokenType == operationToken && | ||||
| 		tokens[index+1].Operation.OperationType == traversePathOpType { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user