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
							
								
									9e56b364c2
								
							
						
					
					
						commit
						6efe4c4797
					
				| @ -79,3 +79,14 @@ 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 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ func (p *expressionParserImpl) createExpressionTree(postFixPath []*Operation) (* | |||||||
| 		stack = append(stack, &newNode) | 		stack = append(stack, &newNode) | ||||||
| 	} | 	} | ||||||
| 	if len(stack) != 1 { | 	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 | 	return stack[0], nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -38,5 +38,5 @@ func TestPathTreeOneArgForOneArgOp(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| func TestPathTreeExtraArgs(t *testing.T) { | func TestPathTreeExtraArgs(t *testing.T) { | ||||||
| 	_, err := NewExpressionParser().ParseExpression("sortKeys(.) explode(.)") | 	_, 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 | 				opener = openCollectObject | ||||||
| 				collectOperator = collectObjectOpType | 				collectOperator = collectObjectOpType | ||||||
| 			} | 			} | ||||||
| 			itemsInMiddle := false | 
 | ||||||
| 			for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener { | 			for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener { | ||||||
| 				opStack, result = popOpToResult(opStack, result) | 				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 { | 			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") | ||||||
| @ -61,16 +55,11 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope | |||||||
| 			log.Debugf("deleteing open bracket from opstack") | 			log.Debugf("deleteing open bracket from opstack") | ||||||
| 
 | 
 | ||||||
| 			//and append a collect to the 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}) | 			result = append(result, &Operation{OperationType: collectOperator}) | ||||||
| 			log.Debugf("put collect onto the result") | 			log.Debugf("put collect onto the result") | ||||||
| 			result = append(result, &Operation{OperationType: shortPipeOpType}) | 			result = append(result, &Operation{OperationType: shortPipeOpType}) | ||||||
| 			log.Debugf("put shortpipe onto the result") | 			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) | ||||||
|  | |||||||
| @ -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", "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]`, | 		`.b[.a]`, | ||||||
| 		append(make([]interface{}, 0), "b", "TRAVERSE_ARRAY", "[", "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"), | 		append(make([]interface{}, 0), "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		`.a[]`, | 		`.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"), | 		append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		`.a.[]`, | 		`.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"), | 		append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"), | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| @ -54,7 +64,7 @@ var pathTests = []struct { | |||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		`.a[].c`, | 		`.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"), | 		append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "c", "SHORT_PIPE"), | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| @ -79,17 +89,17 @@ var pathTests = []struct { | |||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		`.a | .[].b == "apple"`, | 		`.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"), | 		append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "apple (string)", "EQUALS", "PIPE"), | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		`(.a | .[].b) == "apple"`, | 		`(.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"), | 		append(make([]interface{}, 0), "a", "SELF", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "PIPE", "apple (string)", "EQUALS"), | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		`.[] | select(. == "*at")`, | 		`.[] | 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"), | 		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[]}`, | 		`{.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"), | 		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*", "PIPE", "(", "SELF", "ASSIGN_STYLE", "flow (string)", ")"), | ||||||
| 		append(make([]interface{}, 0), "foo*", "SELF", "flow (string)", "ASSIGN_STYLE", "PIPE"), | 		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() | var tokeniser = newExpressionTokeniser() | ||||||
|  | |||||||
| @ -409,6 +409,14 @@ func (p *expressionTokeniserImpl) handleToken(tokens []*token, index int, postPr | |||||||
| 
 | 
 | ||||||
| 	postProcessedTokens = append(postProcessedTokens, currentToken) | 	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 && | 	if index != len(tokens)-1 && currentToken.CheckForPostTraverse && | ||||||
| 		tokens[index+1].TokenType == operationToken && | 		tokens[index+1].TokenType == operationToken && | ||||||
| 		tokens[index+1].Operation.OperationType == traversePathOpType { | 		tokens[index+1].Operation.OperationType == traversePathOpType { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user