diff --git a/pkg/yqlib/doc/operators/multiply-merge.md b/pkg/yqlib/doc/operators/multiply-merge.md index e83936bc..26af6f5a 100644 --- a/pkg/yqlib/doc/operators/multiply-merge.md +++ b/pkg/yqlib/doc/operators/multiply-merge.md @@ -23,13 +23,19 @@ yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' file1.yaml file2.y ``` ## Multiply integers -Running +Given a sample.yml file of: +```yaml +a: 3 +b: 4 +``` +then ```bash -yq eval --null-input '3 * 4' +yq eval '.a *= .b' sample.yml ``` will output ```yaml -12 +a: 12 +b: 4 ``` ## Merge objects together, returning merged result only diff --git a/pkg/yqlib/expression_tokeniser.go b/pkg/yqlib/expression_tokeniser.go index caaf6d15..4be52af1 100644 --- a/pkg/yqlib/expression_tokeniser.go +++ b/pkg/yqlib/expression_tokeniser.go @@ -100,7 +100,7 @@ func assignOpToken(updateAssign bool) lex.Action { } } -func multiplyWithPrefs() lex.Action { +func multiplyWithPrefs(op *operationType) lex.Action { return func(s *lex.Scanner, m *machines.Match) (interface{}, error) { prefs := multiplyPreferences{} options := string(m.Bytes) @@ -117,7 +117,7 @@ func multiplyWithPrefs() lex.Action { prefs.DeepMergeArrays = true } prefs.TraversePrefs.DontFollowAlias = true - op := &Operation{OperationType: multiplyOpType, Value: multiplyOpType.Type, StringValue: options, Preferences: prefs} + op := &Operation{OperationType: op, Value: multiplyOpType.Type, StringValue: options, Preferences: prefs} return &token{TokenType: operationToken, Operation: op}, nil } } @@ -476,9 +476,12 @@ func initLexer() (*lex.Lexer, error) { lexer.Add([]byte(`\]\??`), literalToken(closeCollect, true)) lexer.Add([]byte(`\{`), literalToken(openCollectObject, false)) lexer.Add([]byte(`\}`), literalToken(closeCollectObject, true)) - lexer.Add([]byte(`\*[\+|\?dn]*`), multiplyWithPrefs()) + lexer.Add([]byte(`\*=[\+|\?dn]*`), multiplyWithPrefs(multiplyAssignOpType)) + lexer.Add([]byte(`\*[\+|\?dn]*`), multiplyWithPrefs(multiplyOpType)) + lexer.Add([]byte(`\+`), opToken(addOpType)) lexer.Add([]byte(`\+=`), opToken(addAssignOpType)) + lexer.Add([]byte(`\-`), opToken(subtractOpType)) lexer.Add([]byte(`\-=`), opToken(subtractAssignOpType)) lexer.Add([]byte(`\$[a-zA-Z_-0-9]+`), getVariableOpToken()) diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go index 36d76798..76c73e3a 100644 --- a/pkg/yqlib/lib.go +++ b/pkg/yqlib/lib.go @@ -57,6 +57,8 @@ var assignAnchorOpType = &operationType{Type: "ASSIGN_ANCHOR", NumArgs: 2, Prece var assignAliasOpType = &operationType{Type: "ASSIGN_ALIAS", NumArgs: 2, Precedence: 40, Handler: assignAliasOperator} var multiplyOpType = &operationType{Type: "MULTIPLY", NumArgs: 2, Precedence: 42, Handler: multiplyOperator} +var multiplyAssignOpType = &operationType{Type: "MULTIPLY_ASSIGN", NumArgs: 2, Precedence: 42, Handler: multiplyAssignOperator} + var addOpType = &operationType{Type: "ADD", NumArgs: 2, Precedence: 42, Handler: addOperator} var subtractOpType = &operationType{Type: "SUBTRACT", NumArgs: 2, Precedence: 42, Handler: subtractOperator} var alternativeOpType = &operationType{Type: "ALTERNATIVE", NumArgs: 2, Precedence: 42, Handler: alternativeOperator} diff --git a/pkg/yqlib/operator_multiply.go b/pkg/yqlib/operator_multiply.go index 040cb7c0..26f4a798 100644 --- a/pkg/yqlib/operator_multiply.go +++ b/pkg/yqlib/operator_multiply.go @@ -17,6 +17,21 @@ type multiplyPreferences struct { AssignPrefs assignPreferences } +func createMultiplyOp(prefs interface{}) func(lhs *ExpressionNode, rhs *ExpressionNode) *ExpressionNode { + return func(lhs *ExpressionNode, rhs *ExpressionNode) *ExpressionNode { + return &ExpressionNode{Operation: &Operation{OperationType: multiplyOpType, Preferences: prefs}, + Lhs: lhs, + Rhs: rhs} + } +} + +func multiplyAssignOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { + var multiplyPrefs = expressionNode.Operation.Preferences + expressionNode.Operation.Preferences = nil + + return compoundAssignFunction(d, context, expressionNode, createMultiplyOp(multiplyPrefs)) +} + func multiplyOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("-- MultiplyOperator") return crossFunction(d, context, expressionNode, multiply(expressionNode.Operation.Preferences.(multiplyPreferences)), false) diff --git a/pkg/yqlib/operator_multiply_test.go b/pkg/yqlib/operator_multiply_test.go index 4f83bcd6..a1048ec3 100644 --- a/pkg/yqlib/operator_multiply_test.go +++ b/pkg/yqlib/operator_multiply_test.go @@ -153,9 +153,10 @@ var multiplyOperatorScenarios = []expressionScenario{ }, { description: "Multiply integers", - expression: `3 * 4`, + document: "a: 3\nb: 4", + expression: `.a *= .b`, expected: []string{ - "D0, P[], (!!int)::12\n", + "D0, P[], (doc)::a: 12\nb: 4\n", }, }, {